Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |