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

Side by Side Diff: chrome/browser/extensions/sandboxed_unpacker.cc

Issue 829583002: Validate hash_sha256 checksum on .crx update. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add histogram description. Created 5 years, 11 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
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698