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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « chrome/utility/safe_browsing/mac/udif.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/utility/safe_browsing/mac/udif.h" 5 #include "chrome/utility/safe_browsing/mac/udif.h"
6 6
7 #include <CoreFoundation/CoreFoundation.h> 7 #include <CoreFoundation/CoreFoundation.h>
8 #include <bzlib.h> 8 #include <bzlib.h>
9 #include <libkern/OSByteOrder.h> 9 #include <libkern/OSByteOrder.h>
10 #include <uuid/uuid.h> 10 #include <uuid/uuid.h>
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 // Reserved fields are skipped. 174 // Reserved fields are skipped.
175 ConvertBigEndian(&block->checksum); 175 ConvertBigEndian(&block->checksum);
176 ConvertBigEndian(&block->chunk_count); 176 ConvertBigEndian(&block->chunk_count);
177 // Note: This deliberately does not swap the chunks themselves. 177 // Note: This deliberately does not swap the chunks themselves.
178 } 178 }
179 179
180 // UDIFBlock takes a raw, big-endian block data pointer and stores, in host 180 // UDIFBlock takes a raw, big-endian block data pointer and stores, in host
181 // endian, the data for both the block and the chunk. 181 // endian, the data for both the block and the chunk.
182 class UDIFBlock { 182 class UDIFBlock {
183 public: 183 public:
184 explicit UDIFBlock(const UDIFBlockData* block_data) : block(*block_data) { 184 UDIFBlock() : block_() {}
185 ConvertBigEndian(&block); 185
186 for (uint32_t i = 0; i < block.chunk_count; ++i) { 186 bool ParseBlockData(const UDIFBlockData* block_data, uint16_t sector_size) {
187 chunks.push_back(block_data->chunks[i]); 187 block_ = *block_data;
188 ConvertBigEndian(&chunks[i]); 188 ConvertBigEndian(&block_);
189
190 // Make sure the number of sectors doesn't overflow.
191 auto block_size = base::CheckedNumeric<size_t>(sector_count()) *
192 sector_size;
193 if (!block_size.IsValid()) {
194 DLOG(ERROR) << "UDIF block size overflows";
195 return false;
189 } 196 }
197
198 // Make sure that the chunk data isn't larger than the block reports.
199 base::CheckedNumeric<size_t> chunk_sectors(0);
200 for (uint32_t i = 0; i < block_.chunk_count; ++i) {
201 chunks_.push_back(block_data->chunks[i]);
202 UDIFBlockChunk* chunk = &chunks_[i];
203 ConvertBigEndian(chunk);
204
205 chunk_sectors += chunk->sector_count;
206 if (!chunk_sectors.IsValid() ||
207 chunk_sectors.ValueOrDie() > sector_count()) {
208 DLOG(ERROR) << "Total chunk sectors larger than reported block sectors";
209 return false;
210 }
211
212 auto chunk_end_offset =
213 base::CheckedNumeric<size_t>(chunk->compressed_offset) +
214 chunk->compressed_length;
215 if (!chunk_end_offset.IsValid() ||
216 chunk->compressed_length > block_size.ValueOrDie()) {
217 DLOG(ERROR) << "UDIF chunk data length " << i << " overflows";
218 return false;
219 }
220 }
221
222 return true;
190 } 223 }
191 224
192 uint32_t signature() const { return block.signature; } 225 uint32_t signature() const { return block_.signature; }
193 uint32_t version() const { return block.version; } 226 uint32_t version() const { return block_.version; }
194 uint64_t start_sector() const { return block.start_sector; } 227 uint64_t start_sector() const { return block_.start_sector; }
195 uint64_t sector_count() const { return block.sector_count; } 228 uint64_t sector_count() const { return block_.sector_count; }
196 uint64_t chunk_count() const { return chunks.size(); } 229 uint64_t chunk_count() const { return chunks_.size(); }
197 230
198 const UDIFBlockChunk* chunk(uint32_t i) const { 231 const UDIFBlockChunk* chunk(uint32_t i) const {
199 if (i >= chunk_count()) 232 if (i >= chunk_count())
200 return nullptr; 233 return nullptr;
201 return &chunks[i]; 234 return &chunks_[i];
202 } 235 }
203 236
204 private: 237 private:
205 UDIFBlockData block; 238 UDIFBlockData block_;
206 std::vector<UDIFBlockChunk> chunks; 239 std::vector<UDIFBlockChunk> chunks_;
207 240
208 DISALLOW_COPY_AND_ASSIGN(UDIFBlock); 241 DISALLOW_COPY_AND_ASSIGN(UDIFBlock);
209 }; 242 };
210 243
211 #pragma pack(pop) 244 #pragma pack(pop)
212 245
213 namespace { 246 namespace {
214 247
215 const size_t kSectorSize = 512; 248 const size_t kSectorSize = 512;
216 249
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 374
342 std::unique_ptr<ReadStream> UDIFParser::GetPartitionReadStream( 375 std::unique_ptr<ReadStream> UDIFParser::GetPartitionReadStream(
343 size_t part_number) { 376 size_t part_number) {
344 DCHECK_LT(part_number, blocks_.size()); 377 DCHECK_LT(part_number, blocks_.size());
345 return base::WrapUnique( 378 return base::WrapUnique(
346 new UDIFPartitionReadStream(stream_, block_size_, blocks_[part_number])); 379 new UDIFPartitionReadStream(stream_, block_size_, blocks_[part_number]));
347 } 380 }
348 381
349 bool UDIFParser::ParseBlkx() { 382 bool UDIFParser::ParseBlkx() {
350 UDIFResourceFile trailer; 383 UDIFResourceFile trailer;
351 if (stream_->Seek(-sizeof(trailer), SEEK_END) == -1) 384 off_t trailer_start = stream_->Seek(-sizeof(trailer), SEEK_END);
385 if (trailer_start == -1)
352 return false; 386 return false;
353 387
354 if (!stream_->ReadType(&trailer)) { 388 if (!stream_->ReadType(&trailer)) {
355 DLOG(ERROR) << "Failed to read UDIFResourceFile"; 389 DLOG(ERROR) << "Failed to read UDIFResourceFile";
356 return false; 390 return false;
357 } 391 }
358 ConvertBigEndian(&trailer); 392 ConvertBigEndian(&trailer);
359 393
360 if (trailer.signature != trailer.kSignature) { 394 if (trailer.signature != trailer.kSignature) {
361 DLOG(ERROR) << "blkx signature does not match, is 0x" 395 DLOG(ERROR) << "blkx signature does not match, is 0x"
362 << std::hex << trailer.signature; 396 << std::hex << trailer.signature;
363 return false; 397 return false;
364 } 398 }
365 if (trailer.version != trailer.kVersion) { 399 if (trailer.version != trailer.kVersion) {
366 DLOG(ERROR) << "blkx version does not match, is " << trailer.version; 400 DLOG(ERROR) << "blkx version does not match, is " << trailer.version;
367 return false; 401 return false;
368 } 402 }
369 403
404 auto plist_end = base::CheckedNumeric<size_t>(trailer.plist_offset) +
405 trailer.plist_length;
406 if (!plist_end.IsValid() ||
407 plist_end.ValueOrDie() > base::checked_cast<size_t>(trailer_start)) {
408 DLOG(ERROR) << "blkx plist extends past UDIF trailer";
409 return false;
410 }
411
370 std::vector<uint8_t> plist_bytes(trailer.plist_length, 0); 412 std::vector<uint8_t> plist_bytes(trailer.plist_length, 0);
371 413
372 if (stream_->Seek(trailer.plist_offset, SEEK_SET) == -1) 414 if (stream_->Seek(trailer.plist_offset, SEEK_SET) == -1)
373 return false; 415 return false;
374 416
375 if (!stream_->ReadExact(&plist_bytes[0], trailer.plist_length)) { 417 if (!stream_->ReadExact(&plist_bytes[0], trailer.plist_length)) {
376 DLOG(ERROR) << "Failed to read blkx plist data"; 418 DLOG(ERROR) << "Failed to read blkx plist data";
377 return false; 419 return false;
378 } 420 }
379 421
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 base::mac::CFCast<CFDictionaryRef>(CFArrayGetValueAtIndex(blkx, i)); 469 base::mac::CFCast<CFDictionaryRef>(CFArrayGetValueAtIndex(blkx, i));
428 auto data = base::mac::GetValueFromDictionary<CFDataRef>(block_dictionary, 470 auto data = base::mac::GetValueFromDictionary<CFDataRef>(block_dictionary,
429 CFSTR("Data")); 471 CFSTR("Data"));
430 if (!data) { 472 if (!data) {
431 DLOG(ERROR) << "Skipping block " << i 473 DLOG(ERROR) << "Skipping block " << i
432 << " because it has no Data section"; 474 << " because it has no Data section";
433 continue; 475 continue;
434 } 476 }
435 477
436 // Copy the block table out of the plist. 478 // Copy the block table out of the plist.
437 auto block_data = 479 std::unique_ptr<UDIFBlock> block(new UDIFBlock());
438 reinterpret_cast<const UDIFBlockData*>(CFDataGetBytePtr(data)); 480 if (!block->ParseBlockData(
439 std::unique_ptr<UDIFBlock> block(new UDIFBlock(block_data)); 481 reinterpret_cast<const UDIFBlockData*>(CFDataGetBytePtr(data)),
482 block_size_)) {
483 DLOG(ERROR) << "Failed to parse UDIF block data";
484 return false;
485 }
440 486
441 if (block->signature() != UDIFBlockData::kSignature) { 487 if (block->signature() != UDIFBlockData::kSignature) {
442 DLOG(ERROR) << "Skipping block " << i << " because its signature does not" 488 DLOG(ERROR) << "Skipping block " << i << " because its signature does not"
443 << " match, is 0x" << std::hex << block->signature(); 489 << " match, is 0x" << std::hex << block->signature();
444 continue; 490 continue;
445 } 491 }
446 if (block->version() != UDIFBlockData::kVersion) { 492 if (block->version() != UDIFBlockData::kVersion) {
447 DLOG(ERROR) << "Skipping block " << i << "because its version does not " 493 DLOG(ERROR) << "Skipping block " << i << "because its version does not "
448 << "match, is " << block->version(); 494 << "match, is " << block->version();
449 continue; 495 continue;
(...skipping 23 matching lines...) Expand all
473 } 519 }
474 } 520 }
475 521
476 blocks_.push_back(std::move(block)); 522 blocks_.push_back(std::move(block));
477 partition_names_.push_back(partition_name); 523 partition_names_.push_back(partition_name);
478 } 524 }
479 525
480 return true; 526 return true;
481 } 527 }
482 528
483 bool UDIFParser::ReadBlockChunk(const UDIFBlockChunk* chunk,
484 std::vector<uint8_t>* decompressed_data) {
485 UDIFBlockChunkReadStream chunk_read_stream(stream_, block_size_, chunk);
486 decompressed_data->resize(chunk_read_stream.length_in_bytes());
487 return chunk_read_stream.ReadExact(&(*decompressed_data)[0],
488 decompressed_data->size());
489 }
490
491 namespace { 529 namespace {
492 530
493 UDIFPartitionReadStream::UDIFPartitionReadStream( 531 UDIFPartitionReadStream::UDIFPartitionReadStream(
494 ReadStream* stream, 532 ReadStream* stream,
495 uint16_t block_size, 533 uint16_t block_size,
496 const UDIFBlock* partition_block) 534 const UDIFBlock* partition_block)
497 : stream_(stream), 535 : stream_(stream),
498 block_size_(block_size), 536 block_size_(block_size),
499 block_(partition_block), 537 block_(partition_block),
500 current_chunk_(0), 538 current_chunk_(0),
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 << chunk_->compressed_offset; 827 << chunk_->compressed_offset;
790 return false; 828 return false;
791 } 829 }
792 return true; 830 return true;
793 } 831 }
794 832
795 } // namespace 833 } // namespace
796 834
797 } // namespace dmg 835 } // namespace dmg
798 } // namespace safe_browsing 836 } // namespace safe_browsing
OLDNEW
« 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