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

Commit 895c13fe authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes I9ad08b0d,I7fb1ef4f,I5b24b9d9

* changes:
  liblp: Add ReadImageFromBlob.
  liblp: Refactor ParseMetadata to read from non-descriptors.
  liblp: Always copy geometry to LpMetadata.
parents 15727714 ee4075d8
Loading
Loading
Loading
Loading
+16 −4
Original line number Diff line number Diff line
@@ -38,12 +38,24 @@ std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << LP_METADATA_GEOMETRY_SIZE;
        return nullptr;
    }
    std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd);
    if (!metadata) {
    return ParseMetadata(geometry, fd);
}

std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes) {
    if (bytes < LP_METADATA_GEOMETRY_SIZE) {
        LERROR << __PRETTY_FUNCTION__ << ": " << bytes << " is smaller than geometry header";
        return nullptr;
    }
    metadata->geometry = geometry;
    return metadata;

    LpMetadataGeometry geometry;
    if (!ParseGeometry(data, &geometry)) {
        return nullptr;
    }

    const uint8_t* metadata_buffer =
            reinterpret_cast<const uint8_t*>(data) + LP_METADATA_GEOMETRY_SIZE;
    size_t metadata_buffer_size = bytes - LP_METADATA_GEOMETRY_SIZE;
    return ParseMetadata(geometry, metadata_buffer, metadata_buffer_size);
}

std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
+1 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t bl
                       const std::map<std::string, std::string>& images);
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes);

// Helper to extract safe C++ strings from partition info.
std::string GetPartitionName(const LpMetadataPartition& partition);
+21 −0
Original line number Diff line number Diff line
@@ -394,6 +394,27 @@ TEST(liblp, ImageFiles) {
    ASSERT_NE(imported, nullptr);
}

// Test that we can read images from buffers.
TEST(liblp, ImageFilesInMemory) {
    unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
    ASSERT_NE(builder, nullptr);
    ASSERT_TRUE(AddDefaultPartitions(builder.get()));
    unique_ptr<LpMetadata> exported = builder->Export();

    unique_fd fd(syscall(__NR_memfd_create, "image_file", 0));
    ASSERT_GE(fd, 0);
    ASSERT_TRUE(WriteToImageFile(fd, *exported.get()));

    int64_t offset = SeekFile64(fd, 0, SEEK_CUR);
    ASSERT_GE(offset, 0);
    ASSERT_EQ(SeekFile64(fd, 0, SEEK_SET), 0);

    size_t bytes = static_cast<size_t>(offset);
    std::unique_ptr<char[]> buffer = std::make_unique<char[]>(bytes);
    ASSERT_TRUE(android::base::ReadFully(fd, buffer.get(), bytes));
    ASSERT_NE(ReadFromImageBlob(buffer.get(), bytes), nullptr);
}

class BadWriter {
  public:
    // When requested, write garbage instead of the requested bytes, then
+59 −14
Original line number Diff line number Diff line
@@ -30,9 +30,45 @@
namespace android {
namespace fs_mgr {

// Parse an LpMetadataGeometry from a buffer. The buffer must be at least
// LP_METADATA_GEOMETRY_SIZE bytes in size.
static bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) {
// Helper class for reading descriptors and memory buffers in the same manner.
class Reader {
  public:
    virtual ~Reader(){};
    virtual bool ReadFully(void* buffer, size_t length) = 0;
};

class FileReader final : public Reader {
  public:
    explicit FileReader(int fd) : fd_(fd) {}
    bool ReadFully(void* buffer, size_t length) override {
        return android::base::ReadFully(fd_, buffer, length);
    }

  private:
    int fd_;
};

class MemoryReader final : public Reader {
  public:
    MemoryReader(const void* buffer, size_t size)
        : buffer_(reinterpret_cast<const uint8_t*>(buffer)), size_(size), pos_(0) {}
    bool ReadFully(void* out, size_t length) override {
        if (size_ - pos_ < length) {
            errno = EINVAL;
            return false;
        }
        memcpy(out, buffer_ + pos_, length);
        pos_ += length;
        return true;
    }

  private:
    const uint8_t* buffer_;
    size_t size_;
    size_t pos_;
};

bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) {
    static_assert(sizeof(*geometry) <= LP_METADATA_GEOMETRY_SIZE);
    memcpy(geometry, buffer, sizeof(*geometry));

@@ -171,16 +207,18 @@ static bool ValidateMetadataHeader(const LpMetadataHeader& header) {

// Parse and validate all metadata at the current position in the given file
// descriptor.
std::unique_ptr<LpMetadata> ParseMetadata(int fd) {
static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry,
                                                 Reader* reader) {
    // First read and validate the header.
    std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
    if (!android::base::ReadFully(fd, &metadata->header, sizeof(metadata->header))) {
    if (!reader->ReadFully(&metadata->header, sizeof(metadata->header))) {
        PERROR << __PRETTY_FUNCTION__ << "read " << sizeof(metadata->header) << "bytes failed";
        return nullptr;
    }
    if (!ValidateMetadataHeader(metadata->header)) {
        return nullptr;
    }
    metadata->geometry = geometry;

    LpMetadataHeader& header = metadata->header;

@@ -191,7 +229,7 @@ std::unique_ptr<LpMetadata> ParseMetadata(int fd) {
        LERROR << "Out of memory reading logical partition tables.";
        return nullptr;
    }
    if (!android::base::ReadFully(fd, buffer.get(), header.tables_size)) {
    if (!reader->ReadFully(buffer.get(), header.tables_size)) {
        PERROR << __PRETTY_FUNCTION__ << "read " << header.tables_size << "bytes failed";
        return nullptr;
    }
@@ -231,10 +269,20 @@ std::unique_ptr<LpMetadata> ParseMetadata(int fd) {

        metadata->extents.push_back(extent);
    }

    return metadata;
}

std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, const void* buffer,
                                          size_t size) {
    MemoryReader reader(buffer, size);
    return ParseMetadata(geometry, &reader);
}

std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, int fd) {
    FileReader reader(fd);
    return ParseMetadata(geometry, &reader);
}

std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
                                                uint32_t slot_number) {
    int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
@@ -242,7 +290,7 @@ std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry
        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
        return nullptr;
    }
    return ParseMetadata(fd);
    return ParseMetadata(geometry, fd);
}

std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
@@ -252,7 +300,7 @@ std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry&
        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
        return nullptr;
    }
    return ParseMetadata(fd);
    return ParseMetadata(geometry, fd);
}

std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {
@@ -268,14 +316,11 @@ std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {

    // Read the priamry copy, and if that fails, try the backup.
    std::unique_ptr<LpMetadata> metadata = ReadPrimaryMetadata(fd, geometry, slot_number);
    if (!metadata) {
        metadata = ReadBackupMetadata(fd, geometry, slot_number);
    }
    if (metadata) {
        metadata->geometry = geometry;
    }
        return metadata;
    }
    return ReadBackupMetadata(fd, geometry, slot_number);
}

std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number) {
    android::base::unique_fd fd(open(block_device, O_RDONLY));
+7 −2
Original line number Diff line number Diff line
@@ -26,11 +26,16 @@
namespace android {
namespace fs_mgr {

std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number);
// Parse an LpMetadataGeometry from a buffer. The buffer must be at least
// LP_METADATA_GEOMETRY_SIZE bytes in size.
bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry);

// Helper functions for manually reading geometry and metadata.
std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number);
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, int fd);
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, const void* buffer,
                                          size_t size);
bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
std::unique_ptr<LpMetadata> ParseMetadata(int fd);

// These functions assume a valid geometry and slot number.
std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,