Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(639)

Unified Diff: chrome/utility/safe_browsing/mac/udif.cc

Issue 2141963002: Validate safe_browsing::dmg::UDIFBlock data before attempting to read at its offsets. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address comments Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/utility/safe_browsing/mac/udif.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/utility/safe_browsing/mac/udif.cc
diff --git a/chrome/utility/safe_browsing/mac/udif.cc b/chrome/utility/safe_browsing/mac/udif.cc
index 90fde88ca673dce9d79304dfbc5becff37326b70..d3cadf8bd6a01b94b6683280a211efc5458f3e33 100644
--- a/chrome/utility/safe_browsing/mac/udif.cc
+++ b/chrome/utility/safe_browsing/mac/udif.cc
@@ -181,29 +181,62 @@ static void ConvertBigEndian(UDIFBlockData* block) {
// endian, the data for both the block and the chunk.
class UDIFBlock {
public:
- explicit UDIFBlock(const UDIFBlockData* block_data) : block(*block_data) {
- ConvertBigEndian(&block);
- for (uint32_t i = 0; i < block.chunk_count; ++i) {
- chunks.push_back(block_data->chunks[i]);
- ConvertBigEndian(&chunks[i]);
+ UDIFBlock() : block_() {}
+
+ bool ParseBlockData(const UDIFBlockData* block_data, uint16_t sector_size) {
+ block_ = *block_data;
+ ConvertBigEndian(&block_);
+
+ // Make sure the number of sectors doesn't overflow.
+ auto block_size = base::CheckedNumeric<size_t>(sector_count()) *
+ sector_size;
+ if (!block_size.IsValid()) {
+ DLOG(ERROR) << "UDIF block size overflows";
+ return false;
}
+
+ // Make sure that the chunk data isn't larger than the block reports.
+ base::CheckedNumeric<size_t> chunk_sectors(0);
+ for (uint32_t i = 0; i < block_.chunk_count; ++i) {
+ chunks_.push_back(block_data->chunks[i]);
+ UDIFBlockChunk* chunk = &chunks_[i];
+ ConvertBigEndian(chunk);
+
+ chunk_sectors += chunk->sector_count;
+ if (!chunk_sectors.IsValid() ||
+ chunk_sectors.ValueOrDie() > sector_count()) {
+ DLOG(ERROR) << "Total chunk sectors larger than reported block sectors";
+ return false;
+ }
+
+ auto chunk_end_offset =
+ base::CheckedNumeric<size_t>(chunk->compressed_offset) +
+ chunk->compressed_length;
+ if (!chunk_end_offset.IsValid() ||
+ chunk->compressed_length > block_size.ValueOrDie()) {
+ DLOG(ERROR) << "UDIF chunk data length " << i << " overflows";
+ return false;
+ }
+ }
+
+ return true;
}
- uint32_t signature() const { return block.signature; }
- uint32_t version() const { return block.version; }
- uint64_t start_sector() const { return block.start_sector; }
- uint64_t sector_count() const { return block.sector_count; }
- uint64_t chunk_count() const { return chunks.size(); }
+ uint32_t signature() const { return block_.signature; }
+ uint32_t version() const { return block_.version; }
+ uint64_t start_sector() const { return block_.start_sector; }
+ uint64_t sector_count() const { return block_.sector_count; }
+ uint64_t chunk_count() const { return chunks_.size(); }
const UDIFBlockChunk* chunk(uint32_t i) const {
if (i >= chunk_count())
return nullptr;
- return &chunks[i];
+ return &chunks_[i];
}
private:
- UDIFBlockData block;
- std::vector<UDIFBlockChunk> chunks;
+ UDIFBlockData block_;
+ std::vector<UDIFBlockChunk> chunks_;
DISALLOW_COPY_AND_ASSIGN(UDIFBlock);
};
@@ -348,7 +381,8 @@ std::unique_ptr<ReadStream> UDIFParser::GetPartitionReadStream(
bool UDIFParser::ParseBlkx() {
UDIFResourceFile trailer;
- if (stream_->Seek(-sizeof(trailer), SEEK_END) == -1)
+ off_t trailer_start = stream_->Seek(-sizeof(trailer), SEEK_END);
+ if (trailer_start == -1)
return false;
if (!stream_->ReadType(&trailer)) {
@@ -367,6 +401,14 @@ bool UDIFParser::ParseBlkx() {
return false;
}
+ auto plist_end = base::CheckedNumeric<size_t>(trailer.plist_offset) +
+ trailer.plist_length;
+ if (!plist_end.IsValid() ||
+ plist_end.ValueOrDie() > base::checked_cast<size_t>(trailer_start)) {
+ DLOG(ERROR) << "blkx plist extends past UDIF trailer";
+ return false;
+ }
+
std::vector<uint8_t> plist_bytes(trailer.plist_length, 0);
if (stream_->Seek(trailer.plist_offset, SEEK_SET) == -1)
@@ -434,9 +476,13 @@ bool UDIFParser::ParseBlkx() {
}
// Copy the block table out of the plist.
- auto block_data =
- reinterpret_cast<const UDIFBlockData*>(CFDataGetBytePtr(data));
- std::unique_ptr<UDIFBlock> block(new UDIFBlock(block_data));
+ std::unique_ptr<UDIFBlock> block(new UDIFBlock());
+ if (!block->ParseBlockData(
+ reinterpret_cast<const UDIFBlockData*>(CFDataGetBytePtr(data)),
+ block_size_)) {
+ DLOG(ERROR) << "Failed to parse UDIF block data";
+ return false;
+ }
if (block->signature() != UDIFBlockData::kSignature) {
DLOG(ERROR) << "Skipping block " << i << " because its signature does not"
@@ -480,14 +526,6 @@ bool UDIFParser::ParseBlkx() {
return true;
}
-bool UDIFParser::ReadBlockChunk(const UDIFBlockChunk* chunk,
- std::vector<uint8_t>* decompressed_data) {
- UDIFBlockChunkReadStream chunk_read_stream(stream_, block_size_, chunk);
- decompressed_data->resize(chunk_read_stream.length_in_bytes());
- return chunk_read_stream.ReadExact(&(*decompressed_data)[0],
- decompressed_data->size());
-}
-
namespace {
UDIFPartitionReadStream::UDIFPartitionReadStream(
« no previous file with comments | « chrome/utility/safe_browsing/mac/udif.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698