Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ac5b76d authored by Harsh Abichandani's avatar Harsh Abichandani
Browse files

Added liblp_apis_fuzzer

exec/s: 9393
Test: ./liblp_apis_fuzzer
Bug: 285829660

Change-Id: I9830baf7ffbcffa7571aea75e69d1ced64fe613a
parent 072af6ee
Loading
Loading
Loading
Loading
+143 −0
Original line number Diff line number Diff line
@@ -56,3 +56,146 @@ cc_fuzz {
    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",
   ],
}
+43 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
## Table of contents
+  [liblp_builder_fuzzer](#Builder)
+  [liblp_super_layout_builder_fuzzer](#SuperBuilder)
+  [liblp_apis_fuzzer](#APIs)

# <a  name="Builder"></a> Fuzzer for LiblpBuilder

@@ -91,3 +92,45 @@ SuperLayoutBuilder supports the following parameters:
  $ 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
```
+32 −0
Original line number Diff line number Diff line
#!/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)))
+243 −0
Original line number Diff line number Diff line
/*
 * 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;
}