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

Side by Side Diff: extensions/browser/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: Fix histogram value. Created 5 years, 10 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 "extensions/browser/sandboxed_unpacker.h" 5 #include "extensions/browser/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 "components/crx_file/constants.h" 24 #include "components/crx_file/constants.h"
24 #include "components/crx_file/crx_file.h" 25 #include "components/crx_file/crx_file.h"
25 #include "components/crx_file/id_util.h" 26 #include "components/crx_file/id_util.h"
26 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/utility_process_host.h" 28 #include "content/public/browser/utility_process_host.h"
28 #include "content/public/common/common_param_traits.h" 29 #include "content/public/common/common_param_traits.h"
30 #include "crypto/secure_hash.h"
31 #include "crypto/sha2.h"
29 #include "crypto/signature_verifier.h" 32 #include "crypto/signature_verifier.h"
30 #include "extensions/common/constants.h" 33 #include "extensions/common/constants.h"
31 #include "extensions/common/extension.h" 34 #include "extensions/common/extension.h"
32 #include "extensions/common/extension_l10n_util.h" 35 #include "extensions/common/extension_l10n_util.h"
33 #include "extensions/common/extension_utility_messages.h" 36 #include "extensions/common/extension_utility_messages.h"
34 #include "extensions/common/extensions_client.h" 37 #include "extensions/common/extensions_client.h"
35 #include "extensions/common/file_util.h" 38 #include "extensions/common/file_util.h"
36 #include "extensions/common/manifest_constants.h" 39 #include "extensions/common/manifest_constants.h"
37 #include "extensions/common/manifest_handlers/icons_handler.h" 40 #include "extensions/common/manifest_handlers/icons_handler.h"
41 #include "extensions/common/switches.h"
38 #include "grit/extensions_strings.h" 42 #include "grit/extensions_strings.h"
39 #include "third_party/skia/include/core/SkBitmap.h" 43 #include "third_party/skia/include/core/SkBitmap.h"
40 #include "ui/base/l10n/l10n_util.h" 44 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/gfx/codec/png_codec.h" 45 #include "ui/gfx/codec/png_codec.h"
42 46
43 using base::ASCIIToUTF16; 47 using base::ASCIIToUTF16;
44 using content::BrowserThread; 48 using content::BrowserThread;
45 using content::UtilityProcessHost; 49 using content::UtilityProcessHost;
46 using crx_file::CrxFile; 50 using crx_file::CrxFile;
47 51
48 // The following macro makes histograms that record the length of paths 52 // The following macro makes histograms that record the length of paths
49 // in this file much easier to read. 53 // in this file much easier to read.
50 // Windows has a short max path length. If the path length to a 54 // Windows has a short max path length. If the path length to a
51 // file being unpacked from a CRX exceeds the max length, we might 55 // file being unpacked from a CRX exceeds the max length, we might
52 // fail to install. To see if this is happening, see how long the 56 // fail to install. To see if this is happening, see how long the
53 // path to the temp unpack directory is. See crbug.com/69693 . 57 // path to the temp unpack directory is. See crbug.com/69693 .
54 #define PATH_LENGTH_HISTOGRAM(name, path) \ 58 #define PATH_LENGTH_HISTOGRAM(name, path) \
55 UMA_HISTOGRAM_CUSTOM_COUNTS(name, path.value().length(), 0, 500, 100) 59 UMA_HISTOGRAM_CUSTOM_COUNTS(name, path.value().length(), 0, 500, 100)
56 60
57 // Record a rate (kB per second) at which extensions are unpacked. 61 // Record a rate (kB per second) at which extensions are unpacked.
58 // Range from 1kB/s to 100mB/s. 62 // Range from 1kB/s to 100mB/s.
59 #define UNPACK_RATE_HISTOGRAM(name, rate) \ 63 #define UNPACK_RATE_HISTOGRAM(name, rate) \
60 UMA_HISTOGRAM_CUSTOM_COUNTS(name, rate, 1, 100000, 100); 64 UMA_HISTOGRAM_CUSTOM_COUNTS(name, rate, 1, 100000, 100);
61 65
66 // Record if the .crx hash sum is the same as in the updater manifest.
67 #define CRX_HASH_CHECK_HISTOGRAM(name, success) \
Ilya Sherman 2015/02/03 21:40:29 Why do you need a wrapper macro?
68 UMA_HISTOGRAM_BOOLEAN(name, success)
69
62 namespace extensions { 70 namespace extensions {
63 namespace { 71 namespace {
64 72
65 void RecordSuccessfulUnpackTimeHistograms(const base::FilePath& crx_path, 73 void RecordSuccessfulUnpackTimeHistograms(const base::FilePath& crx_path,
66 const base::TimeDelta unpack_time) { 74 const base::TimeDelta unpack_time) {
67 const int64 kBytesPerKb = 1024; 75 const int64 kBytesPerKb = 1024;
68 const int64 kBytesPerMb = 1024 * 1024; 76 const int64 kBytesPerMb = 1024 * 1024;
69 77
70 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackSuccessTime", unpack_time); 78 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackSuccessTime", unpack_time);
71 79
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 return false; 210 return false;
203 211
204 IPC::Message pickle(file_str.data(), file_str.size()); 212 IPC::Message pickle(file_str.data(), file_str.size());
205 PickleIterator iter(pickle); 213 PickleIterator iter(pickle);
206 return IPC::ReadParam(&pickle, &iter, catalogs); 214 return IPC::ReadParam(&pickle, &iter, catalogs);
207 } 215 }
208 216
209 } // namespace 217 } // namespace
210 218
211 SandboxedUnpacker::SandboxedUnpacker( 219 SandboxedUnpacker::SandboxedUnpacker(
212 const base::FilePath& crx_path, 220 const CRXFileInfo& file,
213 Manifest::Location location, 221 Manifest::Location location,
214 int creation_flags, 222 int creation_flags,
215 const base::FilePath& extensions_dir, 223 const base::FilePath& extensions_dir,
216 const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner, 224 const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner,
217 SandboxedUnpackerClient* client) 225 SandboxedUnpackerClient* client)
218 : crx_path_(crx_path), 226 : crx_path_(file.path),
227 package_hash_(file.hash),
228 check_crx_hash_(false),
219 client_(client), 229 client_(client),
220 extensions_dir_(extensions_dir), 230 extensions_dir_(extensions_dir),
221 got_response_(false), 231 got_response_(false),
222 location_(location), 232 location_(location),
223 creation_flags_(creation_flags), 233 creation_flags_(creation_flags),
224 unpacker_io_task_runner_(unpacker_io_task_runner) { 234 unpacker_io_task_runner_(unpacker_io_task_runner) {
235 if (!package_hash_.empty()) {
236 check_crx_hash_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
237 extensions::switches::kEnableCrxHashCheck);
238 }
225 } 239 }
226 240
227 bool SandboxedUnpacker::CreateTempDirectory() { 241 bool SandboxedUnpacker::CreateTempDirectory() {
228 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 242 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
229 243
230 base::FilePath temp_dir; 244 base::FilePath temp_dir;
231 if (!FindWritableTempLocation(extensions_dir_, &temp_dir)) { 245 if (!FindWritableTempLocation(extensions_dir_, &temp_dir)) {
232 ReportFailure(COULD_NOT_GET_TEMP_DIRECTORY, 246 ReportFailure(COULD_NOT_GET_TEMP_DIRECTORY,
233 l10n_util::GetStringFUTF16( 247 l10n_util::GetStringFUTF16(
234 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 248 IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 } 409 }
396 410
397 void SandboxedUnpacker::OnUnpackExtensionFailed(const base::string16& error) { 411 void SandboxedUnpacker::OnUnpackExtensionFailed(const base::string16& error) {
398 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 412 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
399 got_response_ = true; 413 got_response_ = true;
400 ReportFailure( 414 ReportFailure(
401 UNPACKER_CLIENT_FAILED, 415 UNPACKER_CLIENT_FAILED,
402 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error)); 416 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error));
403 } 417 }
404 418
419 static size_t ReadAndHash(void* ptr,
420 size_t size,
421 size_t nmemb,
422 FILE* stream,
423 scoped_ptr<crypto::SecureHash>& hash) {
424 size_t len = fread(ptr, size, nmemb, stream);
425 if (len > 0 && hash) {
426 hash->Update(ptr, len * size);
427 }
428 return len;
429 }
430
431 bool SandboxedUnpacker::FinalizeHash(scoped_ptr<crypto::SecureHash>& hash) {
432 if (hash) {
433 uint8 output[crypto::kSHA256Length];
434 hash->Finish(output, sizeof(output));
435 if (base::StringToLowerASCII(base::HexEncode(output, sizeof(output))) !=
436 package_hash_) {
437 // Package hash verification failed
438 CRX_HASH_CHECK_HISTOGRAM("Extensions.SandboxUnpackHashCheck", false);
439 if (check_crx_hash_) {
440 std::string name = crx_path_.BaseName().AsUTF8Unsafe();
441 LOG(ERROR) << "Hash check failed for extension: " << name;
442 ReportFailure(CRX_HASH_VERIFICATION_FAILED,
443 l10n_util::GetStringFUTF16(
444 IDS_EXTENSION_PACKAGE_ERROR_CODE,
445 ASCIIToUTF16("CRX_HASH_VERIFICATION_FAILED")));
446 return false;
447 }
448 } else {
449 CRX_HASH_CHECK_HISTOGRAM("Extensions.SandboxUnpackHashCheck", true);
Ilya Sherman 2015/02/03 21:40:29 I'd recommend having a single code path per histog
450 }
451 }
452
453 return true;
454 }
455
405 bool SandboxedUnpacker::ValidateSignature() { 456 bool SandboxedUnpacker::ValidateSignature() {
406 base::ScopedFILE file(base::OpenFile(crx_path_, "rb")); 457 base::ScopedFILE file(base::OpenFile(crx_path_, "rb"));
407 458
459 scoped_ptr<crypto::SecureHash> hash;
460
461 if (!package_hash_.empty()) {
462 hash.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256));
463 }
464
408 if (!file.get()) { 465 if (!file.get()) {
409 // Could not open crx file for reading. 466 // Could not open crx file for reading.
410 #if defined(OS_WIN) 467 #if defined(OS_WIN)
411 // On windows, get the error code. 468 // On windows, get the error code.
412 uint32 error_code = ::GetLastError(); 469 uint32 error_code = ::GetLastError();
413 // TODO(skerner): Use this histogram to understand why so many 470 // TODO(skerner): Use this histogram to understand why so many
414 // windows users hit this error. crbug.com/69693 471 // windows users hit this error. crbug.com/69693
415 472
416 // Windows errors are unit32s, but all of likely errors are in 473 // Windows errors are unit32s, but all of likely errors are in
417 // [1, 1000]. See winerror.h for the meaning of specific values. 474 // [1, 1000]. See winerror.h for the meaning of specific values.
(...skipping 12 matching lines...) Expand all
430 ASCIIToUTF16("CRX_FILE_NOT_READABLE"))); 487 ASCIIToUTF16("CRX_FILE_NOT_READABLE")));
431 return false; 488 return false;
432 } 489 }
433 490
434 // Read and verify the header. 491 // Read and verify the header.
435 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it 492 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it
436 // appears that we don't have any endian/alignment aware serialization 493 // appears that we don't have any endian/alignment aware serialization
437 // code in the code base. So for now, this assumes that we're running 494 // code in the code base. So for now, this assumes that we're running
438 // on a little endian machine with 4 byte alignment. 495 // on a little endian machine with 4 byte alignment.
439 CrxFile::Header header; 496 CrxFile::Header header;
440 size_t len = fread(&header, 1, sizeof(header), file.get()); 497 size_t len = ReadAndHash(&header, 1, sizeof(header), file.get(), hash);
441 if (len < sizeof(header)) { 498 if (len < sizeof(header)) {
442 // Invalid crx header 499 // Invalid crx header
443 ReportFailure(CRX_HEADER_INVALID, l10n_util::GetStringFUTF16( 500 ReportFailure(CRX_HEADER_INVALID, l10n_util::GetStringFUTF16(
444 IDS_EXTENSION_PACKAGE_ERROR_CODE, 501 IDS_EXTENSION_PACKAGE_ERROR_CODE,
445 ASCIIToUTF16("CRX_HEADER_INVALID"))); 502 ASCIIToUTF16("CRX_HEADER_INVALID")));
446 return false; 503 return false;
447 } 504 }
448 505
449 CrxFile::Error error; 506 CrxFile::Error error;
450 scoped_ptr<CrxFile> crx(CrxFile::Parse(header, &error)); 507 scoped_ptr<CrxFile> crx(CrxFile::Parse(header, &error));
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 l10n_util::GetStringFUTF16( 542 l10n_util::GetStringFUTF16(
486 IDS_EXTENSION_PACKAGE_ERROR_CODE, 543 IDS_EXTENSION_PACKAGE_ERROR_CODE,
487 ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH"))); 544 ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH")));
488 break; 545 break;
489 } 546 }
490 return false; 547 return false;
491 } 548 }
492 549
493 std::vector<uint8> key; 550 std::vector<uint8> key;
494 key.resize(header.key_size); 551 key.resize(header.key_size);
495 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); 552 len = ReadAndHash(&key.front(), sizeof(uint8), header.key_size, file.get(),
553 hash);
496 if (len < header.key_size) { 554 if (len < header.key_size) {
497 // Invalid public key 555 // Invalid public key
498 ReportFailure( 556 ReportFailure(
499 CRX_PUBLIC_KEY_INVALID, 557 CRX_PUBLIC_KEY_INVALID,
500 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_CODE, 558 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_CODE,
501 ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID"))); 559 ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID")));
502 return false; 560 return false;
503 } 561 }
504 562
505 std::vector<uint8> signature; 563 std::vector<uint8> signature;
506 signature.resize(header.signature_size); 564 signature.resize(header.signature_size);
507 len = fread(&signature.front(), sizeof(uint8), header.signature_size, 565 len = ReadAndHash(&signature.front(), sizeof(uint8), header.signature_size,
508 file.get()); 566 file.get(), hash);
509 if (len < header.signature_size) { 567 if (len < header.signature_size) {
510 // Invalid signature 568 // Invalid signature
511 ReportFailure( 569 ReportFailure(
512 CRX_SIGNATURE_INVALID, 570 CRX_SIGNATURE_INVALID,
513 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_CODE, 571 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_CODE,
514 ASCIIToUTF16("CRX_SIGNATURE_INVALID"))); 572 ASCIIToUTF16("CRX_SIGNATURE_INVALID")));
515 return false; 573 return false;
516 } 574 }
517 575
518 crypto::SignatureVerifier verifier; 576 crypto::SignatureVerifier verifier;
519 if (!verifier.VerifyInit( 577 if (!verifier.VerifyInit(
520 crx_file::kSignatureAlgorithm, sizeof(crx_file::kSignatureAlgorithm), 578 crx_file::kSignatureAlgorithm, sizeof(crx_file::kSignatureAlgorithm),
521 &signature.front(), signature.size(), &key.front(), key.size())) { 579 &signature.front(), signature.size(), &key.front(), key.size())) {
522 // Signature verification initialization failed. This is most likely 580 // Signature verification initialization failed. This is most likely
523 // caused by a public key in the wrong format (should encode algorithm). 581 // caused by a public key in the wrong format (should encode algorithm).
524 ReportFailure( 582 ReportFailure(
525 CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED, 583 CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED,
526 l10n_util::GetStringFUTF16( 584 l10n_util::GetStringFUTF16(
527 IDS_EXTENSION_PACKAGE_ERROR_CODE, 585 IDS_EXTENSION_PACKAGE_ERROR_CODE,
528 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED"))); 586 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED")));
529 return false; 587 return false;
530 } 588 }
531 589
532 unsigned char buf[1 << 12]; 590 unsigned char buf[1 << 12];
533 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) 591 while ((len = ReadAndHash(buf, 1, sizeof(buf), file.get(), hash)) > 0)
534 verifier.VerifyUpdate(buf, len); 592 verifier.VerifyUpdate(buf, len);
535 593
536 if (!verifier.VerifyFinal()) { 594 if (!verifier.VerifyFinal()) {
537 // Signature verification failed 595 // Signature verification failed
538 ReportFailure(CRX_SIGNATURE_VERIFICATION_FAILED, 596 ReportFailure(CRX_SIGNATURE_VERIFICATION_FAILED,
539 l10n_util::GetStringFUTF16( 597 l10n_util::GetStringFUTF16(
540 IDS_EXTENSION_PACKAGE_ERROR_CODE, 598 IDS_EXTENSION_PACKAGE_ERROR_CODE,
541 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED"))); 599 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED")));
542 return false; 600 return false;
543 } 601 }
544 602
603 if (!FinalizeHash(hash)) {
604 return false;
605 }
606
545 std::string public_key = 607 std::string public_key =
546 std::string(reinterpret_cast<char*>(&key.front()), key.size()); 608 std::string(reinterpret_cast<char*>(&key.front()), key.size());
547 base::Base64Encode(public_key, &public_key_); 609 base::Base64Encode(public_key, &public_key_);
548 610
549 extension_id_ = crx_file::id_util::GenerateId(public_key); 611 extension_id_ = crx_file::id_util::GenerateId(public_key);
550 612
551 return true; 613 return true;
552 } 614 }
553 615
554 void SandboxedUnpacker::ReportFailure(FailureReason reason, 616 void SandboxedUnpacker::ReportFailure(FailureReason reason,
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
783 845
784 void SandboxedUnpacker::Cleanup() { 846 void SandboxedUnpacker::Cleanup() {
785 DCHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 847 DCHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
786 if (!temp_dir_.Delete()) { 848 if (!temp_dir_.Delete()) {
787 LOG(WARNING) << "Can not delete temp directory at " 849 LOG(WARNING) << "Can not delete temp directory at "
788 << temp_dir_.path().value(); 850 << temp_dir_.path().value();
789 } 851 }
790 } 852 }
791 853
792 } // namespace extensions 854 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698