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
This commit is contained in:
Kelvin Zhang 2020-09-17 11:32:29 -04:00
parent a35202befd
commit d1ba38f7c9
7 changed files with 68 additions and 7 deletions

View file

@ -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) {

View file

@ -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);

View file

@ -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());

View file

@ -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);

View file

@ -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 =

View file

@ -137,6 +137,13 @@ bool TargetFile::ReadEntryToString(const std::string_view name, std::string* con
return true;
}
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 false;
}
content->resize(entry.uncompressed_length);
if (auto extract_err = ExtractToMemory(
handle_, &entry, reinterpret_cast<uint8_t*>(&content->at(0)), entry.uncompressed_length);

View file

@ -170,7 +170,12 @@ bool Updater::ReadEntryToString(ZipArchiveHandle za, const std::string& entry_na
<< " in the package: " << ErrorCodeString(find_err);
return false;
}
if (entry.uncompressed_length > std::numeric_limits<size_t>::max()) {
LOG(ERROR) << "Failed to extract " << entry_name
<< " because's uncompressed size exceeds size of address space. "
<< entry.uncompressed_length;
return false;
}
content->resize(entry.uncompressed_length);
int extract_err = ExtractToMemory(za, &entry, reinterpret_cast<uint8_t*>(&content->at(0)),
entry.uncompressed_length);