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

Commit d1ba38f7 authored by Kelvin Zhang's avatar Kelvin Zhang
Browse files

Check for overflow before allocating memory fore decompression.

On 32bit devices, an ZipEntry64 may have size > 2^32, we should check
for such cases before attempting to allocate memory.

Test: mm -j
Change-Id: I0f916ef4b2a692f167719a74bd6ff2e887c6c2ce
parent a35202be
Loading
Loading
Loading
Loading
+30 −4
Original line number Diff line number Diff line
@@ -712,8 +712,14 @@ bool ZipModeImage::InitializeChunks(const std::string& filename, ZipArchiveHandl
    // Add the end of zip file (mainly central directory) as a normal chunk.
    size_t entries_end = 0;
    if (!temp_entries.empty()) {
      entries_end = static_cast<size_t>(temp_entries.back().second.offset +
                                        temp_entries.back().second.compressed_length);
      CHECK_GE(temp_entries.back().second.offset, 0);
      if (__builtin_add_overflow(temp_entries.back().second.offset,
                                 temp_entries.back().second.compressed_length, &entries_end)) {
        LOG(ERROR) << "`entries_end` overflows on entry with offset "
                   << temp_entries.back().second.offset << " and compressed_length "
                   << temp_entries.back().second.compressed_length;
        return false;
      }
    }
    CHECK_LT(entries_end, file_content_.size());
    chunks_.emplace_back(CHUNK_NORMAL, entries_end, &file_content_,
@@ -735,8 +741,16 @@ bool ZipModeImage::InitializeChunks(const std::string& filename, ZipArchiveHandl
        LOG(ERROR) << "Failed to add " << entry_name << " to target chunks";
        return false;
      }

      pos += temp_entries[nextentry].second.compressed_length;
      if (temp_entries[nextentry].second.compressed_length > std::numeric_limits<size_t>::max()) {
        LOG(ERROR) << "Entry " << name << " compressed size exceeds size of address space. "
                   << entry.compressed_length;
        return false;
      }
      if (__builtin_add_overflow(pos, temp_entries[nextentry].second.compressed_length, &pos)) {
        LOG(ERROR) << "`pos` overflows after adding "
                   << temp_entries[nextentry].second.compressed_length;
        return false;
      }
      ++nextentry;
      continue;
    }
@@ -758,6 +772,12 @@ bool ZipModeImage::InitializeChunks(const std::string& filename, ZipArchiveHandl

bool ZipModeImage::AddZipEntryToChunks(ZipArchiveHandle handle, const std::string& entry_name,
                                       ZipEntry64* entry) {
  if (entry->compressed_length > std::numeric_limits<size_t>::max()) {
    LOG(ERROR) << "Failed to add " << entry_name
               << " because's compressed size exceeds size of address space. "
               << entry->compressed_length;
    return false;
  }
  size_t compressed_len = entry->compressed_length;
  if (compressed_len == 0) return true;

@@ -775,6 +795,12 @@ bool ZipModeImage::AddZipEntryToChunks(ZipArchiveHandle handle, const std::strin
    }
  } else if (entry->method == kCompressDeflated) {
    size_t uncompressed_len = entry->uncompressed_length;
    if (uncompressed_len > std::numeric_limits<size_t>::max()) {
      LOG(ERROR) << "Failed to add " << entry_name
                 << " because's compressed size exceeds size of address space. "
                 << uncompressed_len;
      return false;
    }
    std::vector<uint8_t> uncompressed_data(uncompressed_len);
    int ret = ExtractToMemory(handle, entry, uncompressed_data.data(), uncompressed_len);
    if (ret != 0) {
+7 −1
Original line number Diff line number Diff line
@@ -246,7 +246,13 @@ bool SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int
    LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD_PROPERTIES;
    return false;
  }
  uint32_t properties_entry_length = properties_entry.uncompressed_length;
  auto properties_entry_length = properties_entry.uncompressed_length;
  if (properties_entry_length > std::numeric_limits<size_t>::max()) {
    LOG(ERROR) << "Failed to extract " << AB_OTA_PAYLOAD_PROPERTIES
               << " because's uncompressed size exceeds size of address space. "
               << properties_entry_length;
    return false;
  }
  std::vector<uint8_t> payload_properties(properties_entry_length);
  int32_t err =
      ExtractToMemory(zip, &properties_entry, payload_properties.data(), properties_entry_length);
+6 −0
Original line number Diff line number Diff line
@@ -323,6 +323,12 @@ static std::vector<Certificate> IterateZipEntriesAndSearchForKeys(const ZipArchi
  std::string_view name;
  ZipEntry64 entry;
  while ((iter_status = Next(cookie, &entry, &name)) == 0) {
    if (entry.uncompressed_length > std::numeric_limits<size_t>::max()) {
      LOG(ERROR) << "Failed to extract " << name
                 << " because's uncompressed size exceeds size of address space. "
                 << entry.uncompressed_length;
      return {};
    }
    std::vector<uint8_t> pem_content(entry.uncompressed_length);
    if (int32_t extract_status =
            ExtractToMemory(handle, &entry, pem_content.data(), pem_content.size());
+6 −1
Original line number Diff line number Diff line
@@ -51,7 +51,12 @@ std::vector<std::string> GetWipePartitionList(Package* wipe_package) {
  std::string partition_list_content;
  ZipEntry64 entry;
  if (FindEntry(zip, RECOVERY_WIPE_ENTRY_NAME, &entry) == 0) {
    uint32_t length = entry.uncompressed_length;
    auto length = entry.uncompressed_length;
    if (length > std::numeric_limits<size_t>::max()) {
      LOG(ERROR) << "Failed to extract " << RECOVERY_WIPE_ENTRY_NAME
                 << " because's uncompressed size exceeds size of address space. " << length;
      return {};
    }
    partition_list_content = std::string(length, '\0');
    if (auto err = ExtractToMemory(
            zip, &entry, reinterpret_cast<uint8_t*>(partition_list_content.data()), length);
+6 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <unistd.h>
#include <utime.h>

#include <limits>
#include <memory>
#include <string>
#include <vector>
@@ -172,6 +173,11 @@ Value* PackageExtractFileFn(const char* name, State* state,
    }

    std::string buffer;
    if (entry.uncompressed_length > std::numeric_limits<size_t>::max()) {
      return ErrorAbort(state, kPackageExtractFileFailure,
                        "%s(): Entry `%s` Uncompressed size exceeds size of address space.", name,
                        zip_path.c_str());
    }
    buffer.resize(entry.uncompressed_length);

    int32_t ret =
Loading