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