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

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

Powered by Google App Engine
This is Rietveld 408576698