Merge "V3 writer header" into main
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 996ffd7..24eebdf 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -93,8 +93,8 @@
srcs: [
"builder_test.cpp",
"super_layout_builder_test.cpp",
- "test_partition_opener.cpp",
"utility_test.cpp",
+ ":TestPartitionOpener_group",
],
}
@@ -122,3 +122,8 @@
name: "vts_kernel_liblp_test",
defaults: ["liblp_test_defaults"],
}
+
+filegroup {
+ name: "TestPartitionOpener_group",
+ srcs: [ "test_partition_opener.cpp"],
+}
diff --git a/fs_mgr/liblp/fuzzer/Android.bp b/fs_mgr/liblp/fuzzer/Android.bp
new file mode 100644
index 0000000..a9e3509
--- /dev/null
+++ b/fs_mgr/liblp/fuzzer/Android.bp
@@ -0,0 +1,201 @@
+/*
+ * 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"],
+}
+
+python_binary_host {
+ name: "image_gen_rand",
+ srcs: ["image_gen_rand.py"],
+}
+
+genrule_defaults {
+ name: "test_data_gen_defaults",
+ tools: [
+ "image_gen_rand",
+ ],
+}
+
+// Fake dtb image.
+genrule {
+ name: "test_dtb",
+ defaults: ["test_data_gen_defaults"],
+ out: ["test_dtb.img"],
+ cmd: "$(location image_gen_rand) --seed dtb --length 1024 > $(out)",
+}
+
+// Fake bootconfig image.
+genrule {
+ name: "test_bootconfig",
+ defaults: ["test_data_gen_defaults"],
+ out: ["test_bootconfig.img"],
+ cmd: "$(location image_gen_rand) --seed bootconfig --length 1024 > $(out)",
+}
+
+// Fake vendor ramdisk with type "none".
+genrule {
+ name: "test_vendor_ramdisk_none",
+ defaults: ["test_data_gen_defaults"],
+ out: ["test_vendor_ramdisk_none.img"],
+ cmd: "$(location image_gen_rand) --seed vendor_ramdisk_none --length 1024 > $(out)",
+}
+
+// Fake vendor ramdisk with type "platform".
+genrule {
+ name: "test_vendor_ramdisk_platform",
+ defaults: ["test_data_gen_defaults"],
+ out: ["test_vendor_ramdisk_platform.img"],
+ cmd: "$(location image_gen_rand) --seed vendor_ramdisk_platform --length 1024 > $(out)",
+}
+
+// Fake replacement ramdisk.
+genrule {
+ name: "test_vendor_ramdisk_replace",
+ defaults: ["test_data_gen_defaults"],
+ out: ["test_vendor_ramdisk_replace.img"],
+ cmd: "$(location image_gen_rand) --seed replace --length 3072 > $(out)",
+}
+
+// Genrules for test vendor boot images.
+fastboot_sign_test_image = "$(location avbtool) add_hash_footer --salt 00 --image $(out) " +
+ "--partition_name vendor_boot --partition_size $$(( 1 * 1024 * 1024 ))"
+
+genrule_defaults {
+ name: "test_vendor_boot_gen_defaults",
+ defaults: ["test_data_gen_defaults"],
+ tools: [
+ "avbtool",
+ "mkbootimg",
+ ],
+}
+
+genrule {
+ name: "test_vendor_boot_v3",
+ defaults: ["test_vendor_boot_gen_defaults"],
+ out: ["test_vendor_boot_v3.img"],
+ srcs: [
+ ":test_dtb",
+ ":test_vendor_ramdisk_none",
+ ],
+ cmd: "$(location mkbootimg) --header_version 3 " +
+ "--vendor_ramdisk $(location :test_vendor_ramdisk_none) " +
+ "--dtb $(location :test_dtb) " +
+ "--vendor_boot $(out) && " +
+ fastboot_sign_test_image,
+}
+
+genrule {
+ name: "test_vendor_boot_v4_without_frag",
+ defaults: ["test_vendor_boot_gen_defaults"],
+ out: ["test_vendor_boot_v4_without_frag.img"],
+ srcs: [
+ ":test_dtb",
+ ":test_vendor_ramdisk_none",
+ ":test_bootconfig",
+ ],
+ cmd: "$(location mkbootimg) --header_version 4 " +
+ "--vendor_ramdisk $(location :test_vendor_ramdisk_none) " +
+ "--dtb $(location :test_dtb) " +
+ "--vendor_bootconfig $(location :test_bootconfig) " +
+ "--vendor_boot $(out) && " +
+ fastboot_sign_test_image,
+}
+
+genrule {
+ name: "test_vendor_boot_v4_with_frag",
+ defaults: ["test_vendor_boot_gen_defaults"],
+ out: ["test_vendor_boot_v4_with_frag.img"],
+ srcs: [
+ ":test_dtb",
+ ":test_vendor_ramdisk_none",
+ ":test_vendor_ramdisk_platform",
+ ":test_bootconfig",
+ ],
+ cmd: "$(location mkbootimg) --header_version 4 " +
+ "--dtb $(location :test_dtb) " +
+ "--vendor_bootconfig $(location :test_bootconfig) " +
+ "--ramdisk_type none --ramdisk_name none_ramdisk " +
+ "--vendor_ramdisk_fragment $(location :test_vendor_ramdisk_none) " +
+ "--ramdisk_type platform --ramdisk_name platform_ramdisk " +
+ "--vendor_ramdisk_fragment $(location :test_vendor_ramdisk_platform) " +
+ "--vendor_boot $(out) && " +
+ fastboot_sign_test_image,
+}
+
+cc_fuzz {
+ name: "liblp_apis_fuzzer",
+ srcs: [
+ "liblp_apis_fuzzer.cpp",
+ ":TestPartitionOpener_group",
+ ],
+ defaults: ["liblp_fuzz_defaults"],
+ shared_libs: [
+ "libsparse",
+ ],
+ data: [
+ ":test_dtb",
+ ":test_bootconfig",
+ ":test_vendor_ramdisk_none",
+ ":test_vendor_ramdisk_platform",
+ ":test_vendor_ramdisk_replace",
+ ":test_vendor_boot_v3",
+ ":test_vendor_boot_v4_without_frag",
+ ":test_vendor_boot_v4_with_frag",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+}
diff --git a/fs_mgr/liblp/fuzzer/README.md b/fs_mgr/liblp/fuzzer/README.md
new file mode 100644
index 0000000..f831e2e
--- /dev/null
+++ b/fs_mgr/liblp/fuzzer/README.md
@@ -0,0 +1,136 @@
+# Fuzzers for liblp
+## Table of contents
++ [liblp_builder_fuzzer](#Builder)
++ [liblp_super_layout_builder_fuzzer](#SuperBuilder)
++ [liblp_apis_fuzzer](#APIs)
+
+# <a name="Builder"></a> 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`,<br/> 2.`LP_PARTITION_ATTR_READONLY`,<br/> 3.`LP_PARTITION_ATTR_SLOT_SUFFIXED`,<br/> 4.`LP_PARTITION_ATTR_UPDATED`,<br/> 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
+```
+
+# <a name="SuperBuilder"></a> 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`,<br/> 2.`LP_PARTITION_ATTR_READONLY`,<br/> 3.`LP_PARTITION_ATTR_SLOT_SUFFIXED`,<br/> 4.`LP_PARTITION_ATTR_UPDATED`,<br/> 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
+```
+
+# <a name="APIs"></a> Fuzzer for LiblpApis
+
+LiblpAPIs supports the following parameters:
+1. blockDeviceInfoSize (parameter name: "block_device_info_size")
+2. alignment (parameter name: "alignment")
+3. alignmentOffset (parameter name: "alignment_offset")
+4. logicalBlockSize (parameter name: "logical_block_size")
+5. blockDevSize (parameter name: "blockdev_size")
+6. metadataMaxSize (parameter name: "metadata_max_size")
+7. metadataSlotCount (parameter name: "metadata_slot_count")
+8. blockDeviceInfoName (parameter name: "block_device_info_name")
+9. numSectors (parameter name: "num_sectors")
+10. physicalSector (parameter name: "physical_sector")
+11. sparsify (parameter name: "sparsify")
+12. buffer (parameter name: "data")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`blockDeviceInfoSize`| Integer |Value obtained from FuzzedDataProvider|
+|`alignment`| Integer |Value obtained from FuzzedDataProvider|
+|`alignmentOffset`| Integer |Value obtained from FuzzedDataProvider|
+|`logicalBlockSize`| Integer |Value obtained from FuzzedDataProvider|
+|`blockDevSize`| Integer value in multiples of `LP_SECTOR_SIZE`|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|
+|`blockDeviceInfoName`| 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|
+|`alignment`| Bool |Value obtained from FuzzedDataProvider|
+|`alignment`| Vector |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) liblp_apis_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/liblp_apis_fuzzer/liblp_apis_fuzzer
+```
diff --git a/fs_mgr/liblp/fuzzer/image_gen_rand.py b/fs_mgr/liblp/fuzzer/image_gen_rand.py
new file mode 100644
index 0000000..6e85472
--- /dev/null
+++ b/fs_mgr/liblp/fuzzer/image_gen_rand.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python3
+
+# 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.
+
+"""
+Write given number of random bytes, generated with optional seed.
+"""
+
+import random, argparse
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--seed', help='Seed to random generator')
+ parser.add_argument('--length', type=int, required=True, help='Length of output')
+ args = parser.parse_args()
+
+ if args.seed:
+ random.seed(args.seed)
+
+ print(''.join(chr(random.randrange(0,0xff)) for _ in range(args.length)))
diff --git a/fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp b/fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp
new file mode 100644
index 0000000..b6fbc14
--- /dev/null
+++ b/fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp
@@ -0,0 +1,243 @@
+/*
+ * 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 <android-base/file.h>
+#include <fcntl.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <liblp/builder.h>
+#include <liblp/partition_opener.h>
+#include <linux/memfd.h>
+#include <sys/syscall.h>
+#include <writer.h>
+#include "images.h"
+#include "test_partition_opener.h"
+
+using namespace std;
+using namespace android;
+using namespace android::fs_mgr;
+using unique_fd = android::base::unique_fd;
+
+static constexpr size_t kDiskSize = 131072;
+static constexpr size_t kMetadataSize = 512;
+static constexpr size_t kMetadataSlots = 2;
+static constexpr uint32_t kMaxBytes = 20;
+static constexpr uint32_t kValidAlignment = 0;
+static constexpr uint32_t kValidAlignmentOffset = 0;
+static constexpr uint32_t kValidLogicalBlockSize = 4096;
+static constexpr uint32_t kMinMetadataSize = 0;
+static constexpr uint32_t kMaxMetadataSize = 10000;
+static constexpr uint32_t kMinSlot = 0;
+static constexpr uint32_t kMaxSlot = 10;
+static constexpr uint32_t kMinFactor = 0;
+static constexpr uint32_t kMaxFactor = 10;
+static constexpr uint32_t kMetadataGeometrySize = 4096;
+static constexpr uint64_t kValidNumSectors = 1901568;
+static constexpr uint64_t kValidPhysicalSector = 3608576;
+static constexpr uint64_t kMinSectorValue = 1;
+static constexpr uint64_t kMaxSectorValue = 1000000;
+static constexpr uint64_t kMaxBufferSize = 100000;
+
+const string kImageFile = "image_file";
+const string kSuperName = "super";
+const string kSystemPartitionName = "system";
+const string kPartitionName = "builder_partition";
+const string kSuperPartitionName = "super_partition";
+
+const string kSuffix[] = {"_a", "_b", "a", "b"};
+
+class LiplpApisFuzzer {
+ public:
+ LiplpApisFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+ private:
+ void setupBuilder();
+ BlockDeviceInfo getBlockDevice();
+ FuzzedDataProvider mFdp;
+ unique_ptr<MetadataBuilder> mBuilder;
+ string mBlockDeviceInfoName;
+ string mSuperPartitionName;
+ string mPartitionName;
+ const string mImagePaths[10] = {
+ "data/test_dtb.img",
+ "data/test_bootconfig.img",
+ "data/test_vendor_ramdisk_none.img",
+ "data/test_vendor_ramdisk_platform.img",
+ "data/test_vendor_ramdisk_replace.img",
+ "data/test_vendor_boot_v4_with_frag.img",
+ "data/test_vendor_boot_v4_without_frag.img",
+ "data/test_vendor_boot_v3.img",
+ "dev/null",
+ mFdp.ConsumeRandomLengthString(kMaxBytes),
+ };
+};
+
+BlockDeviceInfo LiplpApisFuzzer::getBlockDevice() {
+ mBlockDeviceInfoName =
+ mFdp.ConsumeBool() ? kSuperName : mFdp.ConsumeRandomLengthString(kMaxBytes);
+ uint64_t blockDeviceInfoSize =
+ mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint64_t>() : kDiskSize;
+ uint32_t alignment = mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>() : kValidAlignment;
+ uint32_t alignmentOffset =
+ mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>() : kValidAlignmentOffset;
+ uint32_t logicalBlockSize =
+ mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>() : kValidLogicalBlockSize;
+
+ BlockDeviceInfo superInfo{mBlockDeviceInfoName, blockDeviceInfoSize, alignment, alignmentOffset,
+ logicalBlockSize};
+ return superInfo;
+}
+
+void LiplpApisFuzzer::setupBuilder() {
+ uint64_t randomBlockDevSize =
+ mFdp.ConsumeIntegralInRange<uint64_t>(kMinFactor, kMaxFactor) * LP_SECTOR_SIZE;
+ uint64_t blockDevSize = mFdp.ConsumeBool() ? randomBlockDevSize : kDiskSize;
+ uint32_t randomMetadataMaxSize =
+ mFdp.ConsumeIntegralInRange<uint32_t>(kMinMetadataSize, kMaxMetadataSize);
+ uint32_t metadataMaxSize = mFdp.ConsumeBool() ? kMetadataSize : randomMetadataMaxSize;
+ uint32_t metadataSlotCount = mFdp.ConsumeIntegralInRange<uint32_t>(kMinSlot, kMaxSlot);
+ mBuilder = MetadataBuilder::New(blockDevSize, metadataMaxSize, metadataSlotCount);
+
+ if (mBuilder.get()) {
+ mBuilder->AddPartition(kSystemPartitionName, LP_PARTITION_ATTR_READONLY);
+
+ mPartitionName =
+ mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : kPartitionName;
+ if (!mPartitionName.size()) {
+ mPartitionName = kPartitionName;
+ }
+ mSuperPartitionName = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes)
+ : kSuperPartitionName;
+ if (!mSuperPartitionName.size()) {
+ mSuperPartitionName = kSuperPartitionName;
+ }
+
+ Partition* super = mBuilder->AddPartition(mSuperPartitionName, LP_PARTITION_ATTR_READONLY);
+ mBuilder->AddPartition(mPartitionName, LP_PARTITION_ATTR_READONLY);
+
+ int64_t numSectors = mFdp.ConsumeBool() ? mFdp.ConsumeIntegralInRange<uint64_t>(
+ kMinSectorValue, kMaxSectorValue)
+ : kValidNumSectors;
+ int64_t physicalSector = mFdp.ConsumeBool() ? mFdp.ConsumeIntegralInRange<uint64_t>(
+ kMinSectorValue, kMaxSectorValue)
+ : kValidPhysicalSector;
+
+ mBuilder->AddLinearExtent(super, mBlockDeviceInfoName, numSectors, physicalSector);
+ }
+}
+
+void LiplpApisFuzzer::process() {
+ BlockDeviceInfo superInfo = getBlockDevice();
+ unique_fd fd(syscall(__NR_memfd_create, "image_file", MFD_ALLOW_SEALING));
+ setupBuilder();
+
+ TestPartitionOpener opener(
+ {{mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : kSuperName, fd}},
+ {{mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : kSuperName,
+ superInfo}});
+
+ if (mBuilder.get()) {
+ unique_ptr<LpMetadata> metadata = mBuilder->Export();
+ const LpMetadata& metadataValue = *metadata.get();
+
+ map<string, string> images = {};
+ if (mFdp.ConsumeBool()) {
+ images[mSuperPartitionName] = mFdp.PickValueInArray(mImagePaths);
+ }
+
+ while (mFdp.remaining_bytes()) {
+ auto invokeAPIs = mFdp.PickValueInArray<const function<void()>>({
+ [&]() { WriteToImageFile(fd, metadataValue); },
+ [&]() { WriteToImageFile(kImageFile.c_str(), metadataValue); },
+ [&]() { FlashPartitionTable(opener, kSuperName, metadataValue); },
+ [&]() {
+ UpdatePartitionTable(opener, mPartitionName, metadataValue,
+ mFdp.ConsumeBool() ? 0 : 1 /* slot_number */);
+ },
+ [&]() {
+ ReadMetadata(mPartitionName, mFdp.ConsumeBool() ? 0 : 1 /* slot_number */);
+ },
+ [&]() { FlashPartitionTable(mPartitionName, metadataValue); },
+ [&]() {
+ UpdatePartitionTable(mPartitionName, metadataValue,
+ mFdp.ConsumeBool() ? 0 : 1 /* slot_number */);
+ },
+ [&]() {
+ WriteToImageFile(kImageFile.c_str(), metadataValue,
+ metadata->geometry.logical_block_size, images,
+ mFdp.ConsumeBool() ? true : false /* sparsify */);
+ },
+
+ [&]() {
+ WriteSplitImageFiles(kImageFile.c_str(), metadataValue,
+ metadata->geometry.logical_block_size, images,
+ mFdp.ConsumeBool() ? true : false /* sparsify */);
+ },
+ [&]() { ReadFromImageFile(kImageFile.c_str()); },
+ [&]() { IsEmptySuperImage(kImageFile.c_str()); },
+ [&]() {
+ uint64_t bufferSize = mFdp.ConsumeIntegralInRange<uint64_t>(
+ 2 * kMetadataGeometrySize, kMaxBufferSize);
+ vector<uint8_t> buffer = mFdp.ConsumeBytes<uint8_t>(kMaxBytes);
+ buffer.resize(bufferSize);
+ ReadFromImageBlob(buffer.data(), buffer.size());
+ },
+ [&]() {
+ uint32_t groupVectorSize = metadata->groups.size();
+ uint32_t randomGroupIndex =
+ mFdp.ConsumeIntegralInRange<uint32_t>(0, groupVectorSize);
+ GetPartitionGroupName(metadata->groups[randomGroupIndex]);
+ },
+ [&]() {
+ uint32_t blockDeviceVectorSize = metadata->block_devices.size();
+ uint32_t randomBlockDeviceIndex =
+ mFdp.ConsumeIntegralInRange<uint32_t>(0, blockDeviceVectorSize);
+ GetBlockDevicePartitionName(
+ metadata->block_devices[randomBlockDeviceIndex]);
+ },
+ [&]() { GetMetadataSuperBlockDevice(metadataValue); },
+ [&]() {
+ string suffix = mFdp.ConsumeBool()
+ ? mFdp.PickValueInArray<string>(kSuffix)
+ : mFdp.ConsumeRandomLengthString(kMaxBytes);
+ SlotNumberForSlotSuffix(suffix);
+ },
+ [&]() {
+ auto entry = FindPartition(metadataValue, kSystemPartitionName);
+ GetPartitionSize(metadataValue, *entry);
+ },
+ [&]() { GetPartitionSlotSuffix(mPartitionName); },
+ [&]() { FindPartition(metadataValue, mPartitionName); },
+ [&]() {
+ uint32_t partitionVectorSize = metadata->partitions.size();
+ uint32_t randomPartitionIndex =
+ mFdp.ConsumeIntegralInRange<uint32_t>(0, partitionVectorSize);
+ GetPartitionName(metadata->partitions[randomPartitionIndex]);
+ },
+ [&]() { GetTotalSuperPartitionSize(metadataValue); },
+ [&]() { GetBlockDevicePartitionNames(metadataValue); },
+ });
+ invokeAPIs();
+ }
+ remove(kImageFile.c_str());
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ LiplpApisFuzzer liplpApisFuzzer(data, size);
+ liplpApisFuzzer.process();
+ return 0;
+}
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 0000000..e5fbe27
--- /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 <fuzzer/FuzzedDataProvider.h>
+#include <liblp/builder.h>
+#include <liblp/property_fetcher.h>
+#include <storage_literals/storage_literals.h>
+
+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<BlockDeviceInfo> mBlockDevices;
+ unique_ptr<MetadataBuilder> 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 <typename T>
+ T getParamValue(T validValue) {
+ T parameter = validValue;
+ if (mFdp.ConsumeBool()) {
+ parameter = mFdp.ConsumeIntegralInRange<T>(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<uint32_t>(kMinSlot, kMaxSlot);
+ mBuilder = MetadataBuilder::New(mBlockDevices, superBlockDeviceName, maxMetadataSize,
+ numSlots);
+ break;
+ }
+ case 1: {
+ uint64_t blockDevSize =
+ mFdp.ConsumeIntegralInRange<uint64_t>(kMinBlockDevValue, kMaxBlockDevValue);
+ uint32_t metadataMaxSize =
+ mFdp.ConsumeIntegralInRange<uint32_t>(kMinMetadataValue, kMaxMetadataValue);
+ uint32_t metadataSlotCount = mFdp.ConsumeIntegralInRange<uint32_t>(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<uint32_t>(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<uint32_t>(0, 1) /* slot_number */);
+ break;
+ }
+ }
+}
+
+void BuilderFuzzer::setupBuilder(string superBlockDeviceName) {
+ uint64_t blockDeviceInfoSize =
+ mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint64_t>() : kValidBlockDeviceInfoSize;
+ uint32_t alignment = mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>() : kValidAlignment;
+ uint32_t alignmentOffset =
+ mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>() : kValidAlignmentOffset;
+ uint32_t logicalBlockSize =
+ mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>() : kValidLogicalBlockSize;
+ BlockDeviceInfo super(superBlockDeviceName, blockDeviceInfoSize, alignment, alignmentOffset,
+ logicalBlockSize);
+ mBlockDevices.push_back(super);
+
+ mBuilder->AddGroup(kDefaultGroupName, mFdp.ConsumeIntegral<uint64_t>() /* 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<uint64_t>() : kBlockDeviceInfoSize /* size */,
+ mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>()
+ : kZeroAlignmentOffset /* alignment */,
+ mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>()
+ : kZeroAlignmentOffset /* alignment_offset */,
+ mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>()
+ : 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<uint32_t>(0, 2);
+ auto sourceBuilder =
+ MetadataBuilder::New(sourceBlockDevSize, sourceMetadataMaxSize, sourceSlotCount);
+
+ uint64_t targetBlockDevSize = getParamValue(kValidBlockSize);
+ uint32_t targetMetadataMaxSize = getParamValue(kValidMetadataSize);
+ uint32_t targetSlotCount = mFdp.ConsumeIntegralInRange<uint32_t>(0, 2);
+ auto targetBuilder =
+ MetadataBuilder::New(targetBlockDevSize, targetMetadataMaxSize, targetSlotCount);
+
+ if (sourceBuilder && targetBuilder) {
+ int64_t sourceGroups = mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
+ for (int64_t idx = 0; idx < sourceGroups; ++idx) {
+ sourceBuilder->AddGroup(
+ mFdp.PickValueInArray(mGroupNames),
+ mFdp.ConsumeBool() ? kValidMaxGroupSize : mFdp.ConsumeIntegral<uint64_t>());
+ }
+
+ int64_t sourcePartitions = mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
+ for (int64_t idx = 0; idx < sourcePartitions; ++idx) {
+ sourceBuilder->AddPartition(mFdp.PickValueInArray(mPartitionNames),
+ LP_PARTITION_ATTR_READONLY);
+ }
+
+ int64_t targetGroups = mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
+ for (int64_t idx = 0; idx < targetGroups; ++idx) {
+ targetBuilder->AddGroup(
+ mFdp.PickValueInArray(mGroupNames),
+ mFdp.ConsumeBool() ? kValidMaxGroupSize : mFdp.ConsumeIntegral<uint64_t>());
+ }
+
+ int64_t targetPartitions = mFdp.ConsumeIntegralInRange<int64_t>(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<string>{"system", "vendor", mFdp.ConsumeRandomLengthString(kMaxBytes)});
+ }
+}
+
+void BuilderFuzzer::invokeBuilderAPIs() {
+ string superBlockDeviceName =
+ mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : kDeviceInfoName;
+ uint32_t randomBuilder = mFdp.ConsumeIntegralInRange<uint32_t>(kMinBuilder, kMaxBuilder);
+ selectRandomBuilder(randomBuilder, superBlockDeviceName);
+
+ if (mBuilder.get()) {
+ setupBuilder(superBlockDeviceName);
+
+ while (mFdp.remaining_bytes()) {
+ auto invokeAPIs = mFdp.PickValueInArray<const function<void()>>({
+ [&]() { callChangePartitionGroup(); },
+ [&]() {
+ string addedGroupName = mFdp.PickValueInArray(mGroupNames);
+ mBuilder->AddGroup(addedGroupName,
+ mFdp.ConsumeIntegralInRange<uint64_t>(
+ kMinValue, kMaxValue) /* max_size */);
+ },
+ [&]() {
+ string partitionName = mFdp.PickValueInArray(mPartitionNames);
+ Partition* addedPartition = mBuilder->AddPartition(
+ partitionName, mFdp.PickValueInArray(kAttributeTypes));
+ },
+ [&]() {
+ int64_t numSectors = mFdp.ConsumeBool()
+ ? mFdp.ConsumeIntegralInRange<uint64_t>(
+ kMinSectorValue, kMaxSectorValue)
+ : kValidNumSectors;
+ int64_t physicalSector = mFdp.ConsumeBool()
+ ? mFdp.ConsumeIntegralInRange<uint64_t>(
+ kMinSectorValue, kMaxSectorValue)
+ : kValidPhysicalSector;
+
+ int64_t numExtents =
+ mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
+ bool extentAdded = false;
+ for (int64_t i = 0; i <= numExtents; ++i) {
+ extentAdded = mBuilder->AddLinearExtent(mFuzzPartition, kDeviceInfoName,
+ numSectors, physicalSector);
+ }
+
+ if (extentAdded) {
+ unique_ptr<LpMetadata> metadata = mBuilder->Export();
+ uint64_t alignedSize =
+ mFdp.ConsumeIntegralInRange<uint64_t>(kMinValue, kMaxValue);
+ mFuzzPartition->GetBeginningExtents(LP_SECTOR_SIZE * numExtents);
+ }
+ },
+ [&]() { callVerifyExtentsAgainstSourceMetadata(); },
+ [&]() { mBuilder->ListPartitionsInGroup(mFdp.PickValueInArray(mGroupNames)); },
+ [&]() {
+ int64_t maxSize = mFdp.ConsumeIntegral<uint64_t>();
+ 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<LpMetadata> 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<LpMetadata> 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<uint64_t>() /* device _index */,
+ mFdp.ConsumeIntegral<uint64_t>() /* start */,
+ mFdp.ConsumeIntegral<uint64_t>()) /* end */,
+ Interval(mFdp.ConsumeIntegral<uint64_t>() /* device _index */,
+ mFdp.ConsumeIntegral<uint64_t>() /* start */,
+ mFdp.ConsumeIntegral<uint64_t>() /* end */));
+ },
+ [&]() {
+ vector<Interval> intervalVectorA;
+ int64_t internalVectorAElements =
+ mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
+ for (int64_t idx = 0; idx < internalVectorAElements; ++idx) {
+ intervalVectorA.push_back(
+ Interval(mFdp.ConsumeIntegral<uint64_t>() /* device _index */,
+ mFdp.ConsumeIntegral<uint64_t>() /* start */,
+ mFdp.ConsumeIntegral<uint64_t>() /* end */));
+ }
+
+ vector<Interval> intervalVectorB;
+ int64_t internalVectorBElements =
+ mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
+ for (int64_t idx = 0; idx < internalVectorBElements; ++idx) {
+ intervalVectorB.push_back(
+ Interval(mFdp.ConsumeIntegral<uint64_t>() /* device _index */,
+ mFdp.ConsumeIntegral<uint64_t>() /* start */,
+ mFdp.ConsumeIntegral<uint64_t>() /* end */));
+ }
+
+ Interval::Intersect(intervalVectorA, intervalVectorB);
+ },
+ [&]() {
+ uint64_t numSectors =
+ mFdp.ConsumeIntegralInRange<uint64_t>(kMinValue, kMaxValue);
+ uint32_t deviceIndex =
+ mFdp.ConsumeIntegralInRange<uint32_t>(kMinValue, kMaxValue);
+ uint64_t physicalSector =
+ mFdp.ConsumeIntegralInRange<uint64_t>(kMinValue, kMaxValue);
+ LinearExtent extent(numSectors, deviceIndex, physicalSector);
+ extent.AsInterval();
+ },
+ [&]() {
+ IPropertyFetcher::OverrideForTesting(std::make_unique<PropertyFetcher>());
+ },
+ });
+ 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 0000000..887093c
--- /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 <android-base/unique_fd.h>
+#include <fcntl.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <liblp/metadata_format.h>
+#include <liblp/super_layout_builder.h>
+#include <linux/memfd.h>
+#include <storage_literals/storage_literals.h>
+#include <sys/syscall.h>
+
+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<MetadataBuilder> mSuperBuilder;
+ unique_ptr<LpMetadata> mMetadata;
+ bool mOpenSuccess = false;
+};
+
+void SuperLayoutBuilderFuzzer::setupSuperLayoutBuilder(string fuzzPartitionName) {
+ uint64_t randomBlockDevSize =
+ mFdp.ConsumeIntegralInRange<uint64_t>(kMinBlockDevValue, kMaxBlockDevValue);
+ uint64_t blockDevSize = mFdp.ConsumeBool() ? kSuperLayoutValidBlockDevSize : randomBlockDevSize;
+ uint32_t randomMetadataMaxSize =
+ mFdp.ConsumeIntegralInRange<uint32_t>(kMinMetadataValue, kMaxMetadataValue);
+ uint32_t metadataMaxSize =
+ mFdp.ConsumeBool() ? kSuperLayoutValidMetadataSize : randomMetadataMaxSize;
+ uint32_t metadataSlotCount = mFdp.ConsumeIntegralInRange<uint32_t>(kMinSlot, kMaxSlot);
+ mSuperBuilder = MetadataBuilder::New(blockDevSize, metadataMaxSize, metadataSlotCount);
+
+ if (mSuperBuilder.get()) {
+ if (mFdp.ConsumeBool()) {
+ int32_t numPartitions =
+ mFdp.ConsumeIntegralInRange<int32_t>(kMinElements, kMaxElements);
+ addMultiplePartitions(numPartitions);
+ }
+
+ uint32_t randomOpen = mFdp.ConsumeIntegralInRange<uint32_t>(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<uint8_t> imageData = mFdp.ConsumeBytes<uint8_t>(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<const function<void()>>({
+ [&]() { mSuperLayoutBuilder.GetImageLayout(); },
+ [&]() {
+ mSuperLayoutBuilder.AddPartition(fuzzPartitionName, imageName,
+ mFdp.ConsumeIntegral<uint64_t>());
+ },
+ });
+ invokeSuperAPIs();
+ }
+ }
+}
+
+void SuperLayoutBuilderFuzzer::process() {
+ invokeSuperLayoutBuilderAPIs();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ SuperLayoutBuilderFuzzer superLayoutBuilderFuzzer(data, size);
+ superLayoutBuilderFuzzer.process();
+ return 0;
+}