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

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: 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 explicit UDIFBlock(uint16_t sector_size)
185 ConvertBigEndian(&block); 185 : sector_size_(sector_size),
186 for (uint32_t i = 0; i < block.chunk_count; ++i) { 186 block_() {}
187 chunks.push_back(block_data->chunks[i]); 187
188 ConvertBigEndian(&chunks[i]); 188 bool ParseBlockData(const UDIFBlockData* block_data) {
189 block_ = *block_data;
190 ConvertBigEndian(&block_);
191
192 // Make sure the number of sectors doesn't overflow.
193 auto block_size = base::CheckedNumeric<size_t>(sector_count()) *
194 sector_size_;
195 if (!block_size.IsValid()) {
196 DLOG(ERROR) << "UDIF block size overflows";
197 return false;
189 } 198 }
199
200 // Make sure that the chunk data isn't larger than the block reports.
201 base::CheckedNumeric<size_t> chunk_sectors(0);
202 for (uint32_t i = 0; i < block_.chunk_count; ++i) {
203 chunks_.push_back(block_data->chunks[i]);
204 UDIFBlockChunk* chunk = &chunks_[i];
205 ConvertBigEndian(chunk);
206
207 chunk_sectors += chunk->sector_count;
208 if (!chunk_sectors.IsValid() ||
209 chunk_sectors.ValueOrDie() > sector_count()) {
210 DLOG(ERROR) << "Total chunk sectors larger than reported block sectors";
211 return false;
212 }
213
214 auto chunk_end_offset =
215 base::CheckedNumeric<size_t>(chunk->compressed_offset) +
216 chunk->compressed_length;
217 if (!chunk_end_offset.IsValid() ||
218 chunk->compressed_length > block_size.ValueOrDie()) {
Mark Mentovai 2016/07/12 15:22:23 Should this be checking that the chunk_end_offset
Robert Sesek 2016/07/12 16:16:35 No, because of the way these values are nested. It
219 DLOG(ERROR) << "UDIF chunk data length " << i << " overflows";
220 return false;
221 }
222 }
223
224 return true;
190 } 225 }
191 226
192 uint32_t signature() const { return block.signature; } 227 uint32_t signature() const { return block_.signature; }
193 uint32_t version() const { return block.version; } 228 uint32_t version() const { return block_.version; }
194 uint64_t start_sector() const { return block.start_sector; } 229 uint64_t start_sector() const { return block_.start_sector; }
195 uint64_t sector_count() const { return block.sector_count; } 230 uint64_t sector_count() const { return block_.sector_count; }
196 uint64_t chunk_count() const { return chunks.size(); } 231 uint64_t chunk_count() const { return chunks_.size(); }
197 232
198 const UDIFBlockChunk* chunk(uint32_t i) const { 233 const UDIFBlockChunk* chunk(uint32_t i) const {
199 if (i >= chunk_count()) 234 if (i >= chunk_count())
200 return nullptr; 235 return nullptr;
201 return &chunks[i]; 236 return &chunks_[i];
202 } 237 }
203 238
204 private: 239 private:
205 UDIFBlockData block; 240 const uint16_t sector_size_;
Mark Mentovai 2016/07/12 15:22:23 Better if this is last, but I don’t think it needs
Robert Sesek 2016/07/12 16:16:35 Done.
206 std::vector<UDIFBlockChunk> chunks; 241 UDIFBlockData block_;
242 std::vector<UDIFBlockChunk> chunks_;
207 243
208 DISALLOW_COPY_AND_ASSIGN(UDIFBlock); 244 DISALLOW_COPY_AND_ASSIGN(UDIFBlock);
209 }; 245 };
210 246
211 #pragma pack(pop) 247 #pragma pack(pop)
212 248
213 namespace { 249 namespace {
214 250
215 const size_t kSectorSize = 512; 251 const size_t kSectorSize = 512;
216 252
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 377
342 std::unique_ptr<ReadStream> UDIFParser::GetPartitionReadStream( 378 std::unique_ptr<ReadStream> UDIFParser::GetPartitionReadStream(
343 size_t part_number) { 379 size_t part_number) {
344 DCHECK_LT(part_number, blocks_.size()); 380 DCHECK_LT(part_number, blocks_.size());
345 return base::WrapUnique( 381 return base::WrapUnique(
346 new UDIFPartitionReadStream(stream_, block_size_, blocks_[part_number])); 382 new UDIFPartitionReadStream(stream_, block_size_, blocks_[part_number]));
347 } 383 }
348 384
349 bool UDIFParser::ParseBlkx() { 385 bool UDIFParser::ParseBlkx() {
350 UDIFResourceFile trailer; 386 UDIFResourceFile trailer;
351 if (stream_->Seek(-sizeof(trailer), SEEK_END) == -1) 387 off_t trailer_start = stream_->Seek(-sizeof(trailer), SEEK_END);
388 if (trailer_start == -1)
352 return false; 389 return false;
353 390
354 if (!stream_->ReadType(&trailer)) { 391 if (!stream_->ReadType(&trailer)) {
355 DLOG(ERROR) << "Failed to read UDIFResourceFile"; 392 DLOG(ERROR) << "Failed to read UDIFResourceFile";
356 return false; 393 return false;
357 } 394 }
358 ConvertBigEndian(&trailer); 395 ConvertBigEndian(&trailer);
359 396
360 if (trailer.signature != trailer.kSignature) { 397 if (trailer.signature != trailer.kSignature) {
361 DLOG(ERROR) << "blkx signature does not match, is 0x" 398 DLOG(ERROR) << "blkx signature does not match, is 0x"
362 << std::hex << trailer.signature; 399 << std::hex << trailer.signature;
363 return false; 400 return false;
364 } 401 }
365 if (trailer.version != trailer.kVersion) { 402 if (trailer.version != trailer.kVersion) {
366 DLOG(ERROR) << "blkx version does not match, is " << trailer.version; 403 DLOG(ERROR) << "blkx version does not match, is " << trailer.version;
367 return false; 404 return false;
368 } 405 }
369 406
407 auto plist_end = base::CheckedNumeric<size_t>(trailer.plist_offset) +
408 trailer.plist_length;
409 if (!plist_end.IsValid() ||
410 plist_end.ValueOrDie() > base::checked_cast<size_t>(trailer_start)) {
411 DLOG(ERROR) << "blkx plist extends past UDIF trailer";
412 return false;
413 }
414
370 std::vector<uint8_t> plist_bytes(trailer.plist_length, 0); 415 std::vector<uint8_t> plist_bytes(trailer.plist_length, 0);
371 416
372 if (stream_->Seek(trailer.plist_offset, SEEK_SET) == -1) 417 if (stream_->Seek(trailer.plist_offset, SEEK_SET) == -1)
373 return false; 418 return false;
374 419
375 if (!stream_->ReadExact(&plist_bytes[0], trailer.plist_length)) { 420 if (!stream_->ReadExact(&plist_bytes[0], trailer.plist_length)) {
376 DLOG(ERROR) << "Failed to read blkx plist data"; 421 DLOG(ERROR) << "Failed to read blkx plist data";
377 return false; 422 return false;
378 } 423 }
379 424
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 base::mac::CFCast<CFDictionaryRef>(CFArrayGetValueAtIndex(blkx, i)); 472 base::mac::CFCast<CFDictionaryRef>(CFArrayGetValueAtIndex(blkx, i));
428 auto data = base::mac::GetValueFromDictionary<CFDataRef>(block_dictionary, 473 auto data = base::mac::GetValueFromDictionary<CFDataRef>(block_dictionary,
429 CFSTR("Data")); 474 CFSTR("Data"));
430 if (!data) { 475 if (!data) {
431 DLOG(ERROR) << "Skipping block " << i 476 DLOG(ERROR) << "Skipping block " << i
432 << " because it has no Data section"; 477 << " because it has no Data section";
433 continue; 478 continue;
434 } 479 }
435 480
436 // Copy the block table out of the plist. 481 // Copy the block table out of the plist.
437 auto block_data = 482 std::unique_ptr<UDIFBlock> block(new UDIFBlock(block_size_));
438 reinterpret_cast<const UDIFBlockData*>(CFDataGetBytePtr(data)); 483 if (!block->ParseBlockData(
439 std::unique_ptr<UDIFBlock> block(new UDIFBlock(block_data)); 484 reinterpret_cast<const UDIFBlockData*>(CFDataGetBytePtr(data)))) {
485 DLOG(ERROR) << "Failed to parse UDIF block data";
486 return false;
487 }
440 488
441 if (block->signature() != UDIFBlockData::kSignature) { 489 if (block->signature() != UDIFBlockData::kSignature) {
442 DLOG(ERROR) << "Skipping block " << i << " because its signature does not" 490 DLOG(ERROR) << "Skipping block " << i << " because its signature does not"
443 << " match, is 0x" << std::hex << block->signature(); 491 << " match, is 0x" << std::hex << block->signature();
444 continue; 492 continue;
445 } 493 }
446 if (block->version() != UDIFBlockData::kVersion) { 494 if (block->version() != UDIFBlockData::kVersion) {
447 DLOG(ERROR) << "Skipping block " << i << "because its version does not " 495 DLOG(ERROR) << "Skipping block " << i << "because its version does not "
448 << "match, is " << block->version(); 496 << "match, is " << block->version();
449 continue; 497 continue;
(...skipping 23 matching lines...) Expand all
473 } 521 }
474 } 522 }
475 523
476 blocks_.push_back(std::move(block)); 524 blocks_.push_back(std::move(block));
477 partition_names_.push_back(partition_name); 525 partition_names_.push_back(partition_name);
478 } 526 }
479 527
480 return true; 528 return true;
481 } 529 }
482 530
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 { 531 namespace {
492 532
493 UDIFPartitionReadStream::UDIFPartitionReadStream( 533 UDIFPartitionReadStream::UDIFPartitionReadStream(
494 ReadStream* stream, 534 ReadStream* stream,
495 uint16_t block_size, 535 uint16_t block_size,
496 const UDIFBlock* partition_block) 536 const UDIFBlock* partition_block)
497 : stream_(stream), 537 : stream_(stream),
498 block_size_(block_size), 538 block_size_(block_size),
499 block_(partition_block), 539 block_(partition_block),
500 current_chunk_(0), 540 current_chunk_(0),
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 << chunk_->compressed_offset; 829 << chunk_->compressed_offset;
790 return false; 830 return false;
791 } 831 }
792 return true; 832 return true;
793 } 833 }
794 834
795 } // namespace 835 } // namespace
796 836
797 } // namespace dmg 837 } // namespace dmg
798 } // namespace safe_browsing 838 } // 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