OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/browser/extensions/sandboxed_unpacker.h" | 5 #include "chrome/browser/extensions/sandboxed_unpacker.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "base/base64.h" | 9 #include "base/base64.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
13 #include "base/files/file_util_proxy.h" | 13 #include "base/files/file_util_proxy.h" |
14 #include "base/files/scoped_file.h" | 14 #include "base/files/scoped_file.h" |
15 #include "base/json/json_string_value_serializer.h" | 15 #include "base/json/json_string_value_serializer.h" |
16 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
17 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
18 #include "base/numerics/safe_conversions.h" | 18 #include "base/numerics/safe_conversions.h" |
19 #include "base/path_service.h" | 19 #include "base/path_service.h" |
20 #include "base/sequenced_task_runner.h" | 20 #include "base/sequenced_task_runner.h" |
21 #include "base/strings/string_number_conversions.h" | |
21 #include "base/strings/utf_string_conversions.h" | 22 #include "base/strings/utf_string_conversions.h" |
22 #include "base/threading/sequenced_worker_pool.h" | 23 #include "base/threading/sequenced_worker_pool.h" |
23 #include "chrome/browser/extensions/extension_service.h" | 24 #include "chrome/browser/extensions/extension_service.h" |
24 #include "chrome/common/chrome_paths.h" | 25 #include "chrome/common/chrome_paths.h" |
25 #include "chrome/common/chrome_switches.h" | 26 #include "chrome/common/chrome_switches.h" |
26 #include "chrome/common/chrome_utility_messages.h" | 27 #include "chrome/common/chrome_utility_messages.h" |
27 #include "chrome/common/extensions/chrome_utility_extensions_messages.h" | 28 #include "chrome/common/extensions/chrome_utility_extensions_messages.h" |
28 #include "chrome/grit/generated_resources.h" | 29 #include "chrome/grit/generated_resources.h" |
29 #include "components/crx_file/constants.h" | 30 #include "components/crx_file/constants.h" |
30 #include "components/crx_file/crx_file.h" | 31 #include "components/crx_file/crx_file.h" |
31 #include "components/crx_file/id_util.h" | 32 #include "components/crx_file/id_util.h" |
32 #include "content/public/browser/browser_thread.h" | 33 #include "content/public/browser/browser_thread.h" |
33 #include "content/public/browser/utility_process_host.h" | 34 #include "content/public/browser/utility_process_host.h" |
34 #include "content/public/common/common_param_traits.h" | 35 #include "content/public/common/common_param_traits.h" |
36 #include "crypto/secure_hash.h" | |
37 #include "crypto/sha2.h" | |
35 #include "crypto/signature_verifier.h" | 38 #include "crypto/signature_verifier.h" |
36 #include "extensions/common/constants.h" | 39 #include "extensions/common/constants.h" |
37 #include "extensions/common/extension.h" | 40 #include "extensions/common/extension.h" |
38 #include "extensions/common/extension_l10n_util.h" | 41 #include "extensions/common/extension_l10n_util.h" |
39 #include "extensions/common/extensions_client.h" | 42 #include "extensions/common/extensions_client.h" |
40 #include "extensions/common/file_util.h" | 43 #include "extensions/common/file_util.h" |
41 #include "extensions/common/manifest_constants.h" | 44 #include "extensions/common/manifest_constants.h" |
42 #include "extensions/common/manifest_handlers/icons_handler.h" | 45 #include "extensions/common/manifest_handlers/icons_handler.h" |
46 #include "extensions/common/switches.h" | |
43 #include "third_party/skia/include/core/SkBitmap.h" | 47 #include "third_party/skia/include/core/SkBitmap.h" |
44 #include "ui/base/l10n/l10n_util.h" | 48 #include "ui/base/l10n/l10n_util.h" |
45 #include "ui/gfx/codec/png_codec.h" | 49 #include "ui/gfx/codec/png_codec.h" |
46 | 50 |
47 using base::ASCIIToUTF16; | 51 using base::ASCIIToUTF16; |
48 using content::BrowserThread; | 52 using content::BrowserThread; |
49 using content::UtilityProcessHost; | 53 using content::UtilityProcessHost; |
50 using crx_file::CrxFile; | 54 using crx_file::CrxFile; |
51 | 55 |
52 // The following macro makes histograms that record the length of paths | 56 // The following macro makes histograms that record the length of paths |
53 // in this file much easier to read. | 57 // in this file much easier to read. |
54 // Windows has a short max path length. If the path length to a | 58 // Windows has a short max path length. If the path length to a |
55 // file being unpacked from a CRX exceeds the max length, we might | 59 // file being unpacked from a CRX exceeds the max length, we might |
56 // fail to install. To see if this is happening, see how long the | 60 // fail to install. To see if this is happening, see how long the |
57 // path to the temp unpack directory is. See crbug.com/69693 . | 61 // path to the temp unpack directory is. See crbug.com/69693 . |
58 #define PATH_LENGTH_HISTOGRAM(name, path) \ | 62 #define PATH_LENGTH_HISTOGRAM(name, path) \ |
59 UMA_HISTOGRAM_CUSTOM_COUNTS(name, path.value().length(), 0, 500, 100) | 63 UMA_HISTOGRAM_CUSTOM_COUNTS(name, path.value().length(), 0, 500, 100) |
60 | 64 |
61 // Record a rate (kB per second) at which extensions are unpacked. | 65 // Record a rate (kB per second) at which extensions are unpacked. |
62 // Range from 1kB/s to 100mB/s. | 66 // Range from 1kB/s to 100mB/s. |
63 #define UNPACK_RATE_HISTOGRAM(name, rate) \ | 67 #define UNPACK_RATE_HISTOGRAM(name, rate) \ |
64 UMA_HISTOGRAM_CUSTOM_COUNTS(name, rate, 1, 100000, 100); | 68 UMA_HISTOGRAM_CUSTOM_COUNTS(name, rate, 1, 100000, 100); |
65 | 69 |
70 // Record if the .crx hash sum is the same as in the updater manifest. | |
71 #define CRX_HASH_CHECK_HISTOGRAM(name, success) \ | |
72 UMA_HISTOGRAM_BOOLEAN(name, success) | |
73 | |
66 namespace extensions { | 74 namespace extensions { |
67 namespace { | 75 namespace { |
68 | 76 |
69 void RecordSuccessfulUnpackTimeHistograms( | 77 void RecordSuccessfulUnpackTimeHistograms( |
70 const base::FilePath& crx_path, const base::TimeDelta unpack_time) { | 78 const base::FilePath& crx_path, const base::TimeDelta unpack_time) { |
71 | 79 |
72 const int64 kBytesPerKb = 1024; | 80 const int64 kBytesPerKb = 1024; |
73 const int64 kBytesPerMb = 1024 * 1024; | 81 const int64 kBytesPerMb = 1024 * 1024; |
74 | 82 |
75 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackSuccessTime", unpack_time); | 83 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackSuccessTime", unpack_time); |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
209 | 217 |
210 IPC::Message pickle(file_str.data(), file_str.size()); | 218 IPC::Message pickle(file_str.data(), file_str.size()); |
211 PickleIterator iter(pickle); | 219 PickleIterator iter(pickle); |
212 return IPC::ReadParam(&pickle, &iter, catalogs); | 220 return IPC::ReadParam(&pickle, &iter, catalogs); |
213 } | 221 } |
214 | 222 |
215 } // namespace | 223 } // namespace |
216 | 224 |
217 SandboxedUnpacker::SandboxedUnpacker( | 225 SandboxedUnpacker::SandboxedUnpacker( |
218 const base::FilePath& crx_path, | 226 const base::FilePath& crx_path, |
227 const std::string& package_hash, | |
219 Manifest::Location location, | 228 Manifest::Location location, |
220 int creation_flags, | 229 int creation_flags, |
221 const base::FilePath& extensions_dir, | 230 const base::FilePath& extensions_dir, |
222 const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner, | 231 const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner, |
223 SandboxedUnpackerClient* client) | 232 SandboxedUnpackerClient* client) |
224 : crx_path_(crx_path), | 233 : crx_path_(crx_path), |
234 package_hash_(package_hash), | |
235 check_crx_hash_(false), | |
225 client_(client), | 236 client_(client), |
226 extensions_dir_(extensions_dir), | 237 extensions_dir_(extensions_dir), |
227 got_response_(false), | 238 got_response_(false), |
228 location_(location), | 239 location_(location), |
229 creation_flags_(creation_flags), | 240 creation_flags_(creation_flags), |
230 unpacker_io_task_runner_(unpacker_io_task_runner) { | 241 unpacker_io_task_runner_(unpacker_io_task_runner) { |
242 if (!package_hash_.empty()) { | |
243 check_crx_hash_ = base::CommandLine::ForCurrentProcess()->HasSwitch( | |
244 extensions::switches::kEnableCrxHashCheck); | |
245 } | |
231 } | 246 } |
232 | 247 |
233 bool SandboxedUnpacker::CreateTempDirectory() { | 248 bool SandboxedUnpacker::CreateTempDirectory() { |
234 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); | 249 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); |
235 | 250 |
236 base::FilePath temp_dir; | 251 base::FilePath temp_dir; |
237 if (!FindWritableTempLocation(extensions_dir_, &temp_dir)) { | 252 if (!FindWritableTempLocation(extensions_dir_, &temp_dir)) { |
238 ReportFailure( | 253 ReportFailure( |
239 COULD_NOT_GET_TEMP_DIRECTORY, | 254 COULD_NOT_GET_TEMP_DIRECTORY, |
240 l10n_util::GetStringFUTF16( | 255 l10n_util::GetStringFUTF16( |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
415 void SandboxedUnpacker::OnUnpackExtensionFailed(const base::string16& error) { | 430 void SandboxedUnpacker::OnUnpackExtensionFailed(const base::string16& error) { |
416 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); | 431 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); |
417 got_response_ = true; | 432 got_response_ = true; |
418 ReportFailure( | 433 ReportFailure( |
419 UNPACKER_CLIENT_FAILED, | 434 UNPACKER_CLIENT_FAILED, |
420 l10n_util::GetStringFUTF16( | 435 l10n_util::GetStringFUTF16( |
421 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, | 436 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, |
422 error)); | 437 error)); |
423 } | 438 } |
424 | 439 |
440 static size_t fread_sha256(void* ptr, | |
441 size_t size, | |
442 size_t nmemb, | |
443 FILE* stream, | |
444 scoped_ptr<crypto::SecureHash>& hash) { | |
445 size_t len = fread(ptr, size, nmemb, stream); | |
446 if (len > 0 && hash) { | |
447 hash->Update(ptr, len * size); | |
448 } | |
449 return len; | |
450 } | |
451 | |
425 bool SandboxedUnpacker::ValidateSignature() { | 452 bool SandboxedUnpacker::ValidateSignature() { |
426 base::ScopedFILE file(base::OpenFile(crx_path_, "rb")); | 453 base::ScopedFILE file(base::OpenFile(crx_path_, "rb")); |
427 | 454 |
455 scoped_ptr<crypto::SecureHash> hash; | |
456 | |
457 if (!package_hash_.empty()) { | |
458 hash.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | |
459 } | |
460 | |
428 if (!file.get()) { | 461 if (!file.get()) { |
429 // Could not open crx file for reading. | 462 // Could not open crx file for reading. |
430 #if defined (OS_WIN) | 463 #if defined (OS_WIN) |
431 // On windows, get the error code. | 464 // On windows, get the error code. |
432 uint32 error_code = ::GetLastError(); | 465 uint32 error_code = ::GetLastError(); |
433 // TODO(skerner): Use this histogram to understand why so many | 466 // TODO(skerner): Use this histogram to understand why so many |
434 // windows users hit this error. crbug.com/69693 | 467 // windows users hit this error. crbug.com/69693 |
435 | 468 |
436 // Windows errors are unit32s, but all of likely errors are in | 469 // Windows errors are unit32s, but all of likely errors are in |
437 // [1, 1000]. See winerror.h for the meaning of specific values. | 470 // [1, 1000]. See winerror.h for the meaning of specific values. |
(...skipping 13 matching lines...) Expand all Loading... | |
451 ASCIIToUTF16("CRX_FILE_NOT_READABLE"))); | 484 ASCIIToUTF16("CRX_FILE_NOT_READABLE"))); |
452 return false; | 485 return false; |
453 } | 486 } |
454 | 487 |
455 // Read and verify the header. | 488 // Read and verify the header. |
456 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it | 489 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it |
457 // appears that we don't have any endian/alignment aware serialization | 490 // appears that we don't have any endian/alignment aware serialization |
458 // code in the code base. So for now, this assumes that we're running | 491 // code in the code base. So for now, this assumes that we're running |
459 // on a little endian machine with 4 byte alignment. | 492 // on a little endian machine with 4 byte alignment. |
460 CrxFile::Header header; | 493 CrxFile::Header header; |
461 size_t len = fread(&header, 1, sizeof(header), file.get()); | 494 size_t len = fread_sha256(&header, 1, sizeof(header), file.get(), hash); |
462 if (len < sizeof(header)) { | 495 if (len < sizeof(header)) { |
463 // Invalid crx header | 496 // Invalid crx header |
464 ReportFailure( | 497 ReportFailure( |
465 CRX_HEADER_INVALID, | 498 CRX_HEADER_INVALID, |
466 l10n_util::GetStringFUTF16( | 499 l10n_util::GetStringFUTF16( |
467 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 500 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
468 ASCIIToUTF16("CRX_HEADER_INVALID"))); | 501 ASCIIToUTF16("CRX_HEADER_INVALID"))); |
469 return false; | 502 return false; |
470 } | 503 } |
471 | 504 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
512 l10n_util::GetStringFUTF16( | 545 l10n_util::GetStringFUTF16( |
513 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 546 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
514 ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH"))); | 547 ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH"))); |
515 break; | 548 break; |
516 } | 549 } |
517 return false; | 550 return false; |
518 } | 551 } |
519 | 552 |
520 std::vector<uint8> key; | 553 std::vector<uint8> key; |
521 key.resize(header.key_size); | 554 key.resize(header.key_size); |
522 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); | 555 len = fread_sha256(&key.front(), sizeof(uint8), header.key_size, file.get(), |
556 hash); | |
523 if (len < header.key_size) { | 557 if (len < header.key_size) { |
524 // Invalid public key | 558 // Invalid public key |
525 ReportFailure( | 559 ReportFailure( |
526 CRX_PUBLIC_KEY_INVALID, | 560 CRX_PUBLIC_KEY_INVALID, |
527 l10n_util::GetStringFUTF16( | 561 l10n_util::GetStringFUTF16( |
528 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 562 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
529 ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID"))); | 563 ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID"))); |
530 return false; | 564 return false; |
531 } | 565 } |
532 | 566 |
533 std::vector<uint8> signature; | 567 std::vector<uint8> signature; |
534 signature.resize(header.signature_size); | 568 signature.resize(header.signature_size); |
535 len = fread(&signature.front(), sizeof(uint8), header.signature_size, | 569 len = fread_sha256(&signature.front(), sizeof(uint8), header.signature_size, |
536 file.get()); | 570 file.get(), hash); |
537 if (len < header.signature_size) { | 571 if (len < header.signature_size) { |
538 // Invalid signature | 572 // Invalid signature |
539 ReportFailure( | 573 ReportFailure( |
540 CRX_SIGNATURE_INVALID, | 574 CRX_SIGNATURE_INVALID, |
541 l10n_util::GetStringFUTF16( | 575 l10n_util::GetStringFUTF16( |
542 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 576 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
543 ASCIIToUTF16("CRX_SIGNATURE_INVALID"))); | 577 ASCIIToUTF16("CRX_SIGNATURE_INVALID"))); |
544 return false; | 578 return false; |
545 } | 579 } |
546 | 580 |
547 crypto::SignatureVerifier verifier; | 581 crypto::SignatureVerifier verifier; |
548 if (!verifier.VerifyInit(crx_file::kSignatureAlgorithm, | 582 if (!verifier.VerifyInit(crx_file::kSignatureAlgorithm, |
549 sizeof(crx_file::kSignatureAlgorithm), | 583 sizeof(crx_file::kSignatureAlgorithm), |
550 &signature.front(), | 584 &signature.front(), |
551 signature.size(), | 585 signature.size(), |
552 &key.front(), | 586 &key.front(), |
553 key.size())) { | 587 key.size())) { |
554 // Signature verification initialization failed. This is most likely | 588 // Signature verification initialization failed. This is most likely |
555 // caused by a public key in the wrong format (should encode algorithm). | 589 // caused by a public key in the wrong format (should encode algorithm). |
556 ReportFailure( | 590 ReportFailure( |
557 CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED, | 591 CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED, |
558 l10n_util::GetStringFUTF16( | 592 l10n_util::GetStringFUTF16( |
559 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 593 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
560 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED"))); | 594 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED"))); |
561 return false; | 595 return false; |
562 } | 596 } |
563 | 597 |
564 unsigned char buf[1 << 12]; | 598 unsigned char buf[1 << 12]; |
565 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) | 599 while ((len = fread_sha256(buf, 1, sizeof(buf), file.get(), hash)) > 0) |
566 verifier.VerifyUpdate(buf, len); | 600 verifier.VerifyUpdate(buf, len); |
567 | 601 |
568 if (!verifier.VerifyFinal()) { | 602 if (!verifier.VerifyFinal()) { |
569 // Signature verification failed | 603 // Signature verification failed |
570 ReportFailure( | 604 ReportFailure( |
571 CRX_SIGNATURE_VERIFICATION_FAILED, | 605 CRX_SIGNATURE_VERIFICATION_FAILED, |
572 l10n_util::GetStringFUTF16( | 606 l10n_util::GetStringFUTF16( |
573 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 607 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
574 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED"))); | 608 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED"))); |
575 return false; | 609 return false; |
576 } | 610 } |
577 | 611 |
612 if (hash) { | |
613 uint8 output3[crypto::kSHA256Length]; | |
Dmitry Polukhin
2015/01/15 12:45:13
Why so strange name 'output3'?
| |
614 hash->Finish(output3, sizeof(output3)); | |
615 if (base::StringToLowerASCII(base::HexEncode(output3, sizeof(output3))) | |
616 != package_hash_) { | |
617 // Package hash verification failed | |
618 CRX_HASH_CHECK_HISTOGRAM("Extensions.SandboxUnpackHashCheck", false); | |
619 if (check_crx_hash_) { | |
Dmitry Polukhin
2015/01/15 12:45:13
I would also print error message to log.
| |
620 ReportFailure( | |
621 CRX_HASH_VERIFICATION_FAILED, | |
622 l10n_util::GetStringFUTF16( | |
623 IDS_EXTENSION_PACKAGE_ERROR_CODE, | |
624 ASCIIToUTF16("CRX_HASH_VERIFICATION_FAILED"))); | |
625 return false; | |
626 } | |
627 } else { | |
628 CRX_HASH_CHECK_HISTOGRAM("Extensions.SandboxUnpackHashCheck", true); | |
629 } | |
630 } | |
631 | |
578 std::string public_key = | 632 std::string public_key = |
579 std::string(reinterpret_cast<char*>(&key.front()), key.size()); | 633 std::string(reinterpret_cast<char*>(&key.front()), key.size()); |
580 base::Base64Encode(public_key, &public_key_); | 634 base::Base64Encode(public_key, &public_key_); |
581 | 635 |
582 extension_id_ = crx_file::id_util::GenerateId(public_key); | 636 extension_id_ = crx_file::id_util::GenerateId(public_key); |
583 | 637 |
584 return true; | 638 return true; |
585 } | 639 } |
586 | 640 |
587 void SandboxedUnpacker::ReportFailure(FailureReason reason, | 641 void SandboxedUnpacker::ReportFailure(FailureReason reason, |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
831 | 885 |
832 void SandboxedUnpacker::Cleanup() { | 886 void SandboxedUnpacker::Cleanup() { |
833 DCHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); | 887 DCHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); |
834 if (!temp_dir_.Delete()) { | 888 if (!temp_dir_.Delete()) { |
835 LOG(WARNING) << "Can not delete temp directory at " | 889 LOG(WARNING) << "Can not delete temp directory at " |
836 << temp_dir_.path().value(); | 890 << temp_dir_.path().value(); |
837 } | 891 } |
838 } | 892 } |
839 | 893 |
840 } // namespace extensions | 894 } // namespace extensions |
OLD | NEW |