Added liblp_builder_fuzzer and liblp_super_layout_builder_fuzzer

exec/s: 17002
Test: ./liblp_builder_fuzzer
exec/s: 31273
Test: ./liblp_super_layout_builder_fuzzer
Bug: 285829660

Change-Id: I05d0a6c72069e500b2c838f9c6d900ca1ce2c8cc
diff --git a/fs_mgr/liblp/fuzzer/Android.bp b/fs_mgr/liblp/fuzzer/Android.bp
new file mode 100644
index 0000000..bdeb377
--- /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 0000000..be9adbd
--- /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)
+
+# <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
+```
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;
+}