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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/sandboxed_unpacker.h" 6 7 #include <set> 8 9 #include "base/base64.h" 10 #include "base/bind.h" 11 #include "base/command_line.h" 12 #include "base/files/file_util.h" 13 #include "base/files/file_util_proxy.h" 14 #include "base/files/scoped_file.h" 15 #include "base/json/json_string_value_serializer.h" 16 #include "base/message_loop/message_loop.h" 17 #include "base/metrics/histogram.h" 18 #include "base/numerics/safe_conversions.h" 19 #include "base/path_service.h" 20 #include "base/sequenced_task_runner.h" 21 #include "base/strings/utf_string_conversions.h" 22 #include "base/threading/sequenced_worker_pool.h" 23 #include "chrome/browser/extensions/extension_service.h" 24 #include "chrome/common/chrome_paths.h" 25 #include "chrome/common/chrome_switches.h" 26 #include "chrome/common/chrome_utility_messages.h" 27 #include "chrome/common/extensions/chrome_utility_extensions_messages.h" 28 #include "chrome/common/extensions/extension_file_util.h" 29 #include "chrome/grit/generated_resources.h" 30 #include "components/crx_file/constants.h" 31 #include "components/crx_file/crx_file.h" 32 #include "components/crx_file/id_util.h" 33 #include "content/public/browser/browser_thread.h" 34 #include "content/public/browser/utility_process_host.h" 35 #include "content/public/common/common_param_traits.h" 36 #include "crypto/signature_verifier.h" 37 #include "extensions/common/constants.h" 38 #include "extensions/common/extension.h" 39 #include "extensions/common/extension_l10n_util.h" 40 #include "extensions/common/file_util.h" 41 #include "extensions/common/manifest_constants.h" 42 #include "extensions/common/manifest_handlers/icons_handler.h" 43 #include "third_party/skia/include/core/SkBitmap.h" 44 #include "ui/base/l10n/l10n_util.h" 45 #include "ui/gfx/codec/png_codec.h" 46 47 using base::ASCIIToUTF16; 48 using content::BrowserThread; 49 using content::UtilityProcessHost; 50 using crx_file::CrxFile; 51 52 // The following macro makes histograms that record the length of paths 53 // in this file much easier to read. 54 // 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 56 // 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 . 58 #define PATH_LENGTH_HISTOGRAM(name, path) \ 59 UMA_HISTOGRAM_CUSTOM_COUNTS(name, path.value().length(), 0, 500, 100) 60 61 // Record a rate (kB per second) at which extensions are unpacked. 62 // Range from 1kB/s to 100mB/s. 63 #define UNPACK_RATE_HISTOGRAM(name, rate) \ 64 UMA_HISTOGRAM_CUSTOM_COUNTS(name, rate, 1, 100000, 100); 65 66 namespace extensions { 67 namespace { 68 69 void RecordSuccessfulUnpackTimeHistograms( 70 const base::FilePath& crx_path, const base::TimeDelta unpack_time) { 71 72 const int64 kBytesPerKb = 1024; 73 const int64 kBytesPerMb = 1024 * 1024; 74 75 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackSuccessTime", unpack_time); 76 77 // To get a sense of how CRX size impacts unpack time, record unpack 78 // time for several increments of CRX size. 79 int64 crx_file_size; 80 if (!base::GetFileSize(crx_path, &crx_file_size)) { 81 UMA_HISTOGRAM_COUNTS("Extensions.SandboxUnpackSuccessCantGetCrxSize", 1); 82 return; 83 } 84 85 // Cast is safe as long as the number of bytes in the CRX is less than 86 // 2^31 * 2^10. 87 int crx_file_size_kb = static_cast<int>(crx_file_size / kBytesPerKb); 88 UMA_HISTOGRAM_COUNTS( 89 "Extensions.SandboxUnpackSuccessCrxSize", crx_file_size_kb); 90 91 // We have time in seconds and file size in bytes. We want the rate bytes are 92 // unpacked in kB/s. 93 double file_size_kb = 94 static_cast<double>(crx_file_size) / static_cast<double>(kBytesPerKb); 95 int unpack_rate_kb_per_s = 96 static_cast<int>(file_size_kb / unpack_time.InSecondsF()); 97 UNPACK_RATE_HISTOGRAM("Extensions.SandboxUnpackRate", unpack_rate_kb_per_s); 98 99 if (crx_file_size < 50.0 * kBytesPerKb) { 100 UNPACK_RATE_HISTOGRAM( 101 "Extensions.SandboxUnpackRateUnder50kB", unpack_rate_kb_per_s); 102 103 } else if (crx_file_size < 1 * kBytesPerMb) { 104 UNPACK_RATE_HISTOGRAM( 105 "Extensions.SandboxUnpackRate50kBTo1mB", unpack_rate_kb_per_s); 106 107 } else if (crx_file_size < 2 * kBytesPerMb) { 108 UNPACK_RATE_HISTOGRAM( 109 "Extensions.SandboxUnpackRate1To2mB", unpack_rate_kb_per_s); 110 111 } else if (crx_file_size < 5 * kBytesPerMb) { 112 UNPACK_RATE_HISTOGRAM( 113 "Extensions.SandboxUnpackRate2To5mB", unpack_rate_kb_per_s); 114 115 } else if (crx_file_size < 10 * kBytesPerMb) { 116 UNPACK_RATE_HISTOGRAM( 117 "Extensions.SandboxUnpackRate5To10mB", unpack_rate_kb_per_s); 118 119 } else { 120 UNPACK_RATE_HISTOGRAM( 121 "Extensions.SandboxUnpackRateOver10mB", unpack_rate_kb_per_s); 122 } 123 } 124 125 // Work horse for FindWritableTempLocation. Creates a temp file in the folder 126 // and uses NormalizeFilePath to check if the path is junction free. 127 bool VerifyJunctionFreeLocation(base::FilePath* temp_dir) { 128 if (temp_dir->empty()) 129 return false; 130 131 base::FilePath temp_file; 132 if (!base::CreateTemporaryFileInDir(*temp_dir, &temp_file)) { 133 LOG(ERROR) << temp_dir->value() << " is not writable"; 134 return false; 135 } 136 // NormalizeFilePath requires a non-empty file, so write some data. 137 // If you change the exit points of this function please make sure all 138 // exit points delete this temp file! 139 if (base::WriteFile(temp_file, ".", 1) != 1) 140 return false; 141 142 base::FilePath normalized_temp_file; 143 bool normalized = base::NormalizeFilePath(temp_file, &normalized_temp_file); 144 if (!normalized) { 145 // If |temp_file| contains a link, the sandbox will block al file system 146 // operations, and the install will fail. 147 LOG(ERROR) << temp_dir->value() << " seem to be on remote drive."; 148 } else { 149 *temp_dir = normalized_temp_file.DirName(); 150 } 151 // Clean up the temp file. 152 base::DeleteFile(temp_file, false); 153 154 return normalized; 155 } 156 157 // This function tries to find a location for unpacking the extension archive 158 // that is writable and does not lie on a shared drive so that the sandboxed 159 // unpacking process can write there. If no such location exists we can not 160 // proceed and should fail. 161 // The result will be written to |temp_dir|. The function will write to this 162 // parameter even if it returns false. 163 bool FindWritableTempLocation(const base::FilePath& extensions_dir, 164 base::FilePath* temp_dir) { 165 // On ChromeOS, we will only attempt to unpack extension in cryptohome (profile) 166 // directory to provide additional security/privacy and speed up the rest of 167 // the extension install process. 168 #if !defined(OS_CHROMEOS) 169 PathService::Get(base::DIR_TEMP, temp_dir); 170 if (VerifyJunctionFreeLocation(temp_dir)) 171 return true; 172 #endif 173 174 *temp_dir = file_util::GetInstallTempDir(extensions_dir); 175 if (VerifyJunctionFreeLocation(temp_dir)) 176 return true; 177 // Neither paths is link free chances are good installation will fail. 178 LOG(ERROR) << "Both the %TEMP% folder and the profile seem to be on " 179 << "remote drives or read-only. Installation can not complete!"; 180 return false; 181 } 182 183 // Read the decoded images back from the file we saved them to. 184 // |extension_path| is the path to the extension we unpacked that wrote the 185 // data. Returns true on success. 186 bool ReadImagesFromFile(const base::FilePath& extension_path, 187 DecodedImages* images) { 188 base::FilePath path = 189 extension_path.AppendASCII(kDecodedImagesFilename); 190 std::string file_str; 191 if (!base::ReadFileToString(path, &file_str)) 192 return false; 193 194 IPC::Message pickle(file_str.data(), file_str.size()); 195 PickleIterator iter(pickle); 196 return IPC::ReadParam(&pickle, &iter, images); 197 } 198 199 // Read the decoded message catalogs back from the file we saved them to. 200 // |extension_path| is the path to the extension we unpacked that wrote the 201 // data. Returns true on success. 202 bool ReadMessageCatalogsFromFile(const base::FilePath& extension_path, 203 base::DictionaryValue* catalogs) { 204 base::FilePath path = extension_path.AppendASCII( 205 kDecodedMessageCatalogsFilename); 206 std::string file_str; 207 if (!base::ReadFileToString(path, &file_str)) 208 return false; 209 210 IPC::Message pickle(file_str.data(), file_str.size()); 211 PickleIterator iter(pickle); 212 return IPC::ReadParam(&pickle, &iter, catalogs); 213 } 214 215 } // namespace 216 217 SandboxedUnpacker::SandboxedUnpacker( 218 const base::FilePath& crx_path, 219 Manifest::Location location, 220 int creation_flags, 221 const base::FilePath& extensions_dir, 222 const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner, 223 SandboxedUnpackerClient* client) 224 : crx_path_(crx_path), 225 client_(client), 226 extensions_dir_(extensions_dir), 227 got_response_(false), 228 location_(location), 229 creation_flags_(creation_flags), 230 unpacker_io_task_runner_(unpacker_io_task_runner) { 231 } 232 233 bool SandboxedUnpacker::CreateTempDirectory() { 234 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 235 236 base::FilePath temp_dir; 237 if (!FindWritableTempLocation(extensions_dir_, &temp_dir)) { 238 ReportFailure( 239 COULD_NOT_GET_TEMP_DIRECTORY, 240 l10n_util::GetStringFUTF16( 241 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 242 ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY"))); 243 return false; 244 } 245 246 if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_dir)) { 247 ReportFailure( 248 COULD_NOT_CREATE_TEMP_DIRECTORY, 249 l10n_util::GetStringFUTF16( 250 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 251 ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY"))); 252 return false; 253 } 254 255 return true; 256 } 257 258 void SandboxedUnpacker::Start() { 259 // We assume that we are started on the thread that the client wants us to do 260 // file IO on. 261 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 262 263 unpack_start_time_ = base::TimeTicks::Now(); 264 265 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackInitialCrxPathLength", 266 crx_path_); 267 if (!CreateTempDirectory()) 268 return; // ReportFailure() already called. 269 270 // Initialize the path that will eventually contain the unpacked extension. 271 extension_root_ = temp_dir_.path().AppendASCII(kTempExtensionName); 272 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackUnpackedCrxPathLength", 273 extension_root_); 274 275 // Extract the public key and validate the package. 276 if (!ValidateSignature()) 277 return; // ValidateSignature() already reported the error. 278 279 // Copy the crx file into our working directory. 280 base::FilePath temp_crx_path = temp_dir_.path().Append(crx_path_.BaseName()); 281 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackTempCrxPathLength", 282 temp_crx_path); 283 284 if (!base::CopyFile(crx_path_, temp_crx_path)) { 285 // Failed to copy extension file to temporary directory. 286 ReportFailure( 287 FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY, 288 l10n_util::GetStringFUTF16( 289 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 290 ASCIIToUTF16("FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY"))); 291 return; 292 } 293 294 // The utility process will have access to the directory passed to 295 // SandboxedUnpacker. That directory should not contain a symlink or NTFS 296 // reparse point. When the path is used, following the link/reparse point 297 // will cause file system access outside the sandbox path, and the sandbox 298 // will deny the operation. 299 base::FilePath link_free_crx_path; 300 if (!base::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) { 301 LOG(ERROR) << "Could not get the normalized path of " 302 << temp_crx_path.value(); 303 ReportFailure( 304 COULD_NOT_GET_SANDBOX_FRIENDLY_PATH, 305 l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED)); 306 return; 307 } 308 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackLinkFreeCrxPathLength", 309 link_free_crx_path); 310 311 BrowserThread::PostTask( 312 BrowserThread::IO, FROM_HERE, 313 base::Bind( 314 &SandboxedUnpacker::StartProcessOnIOThread, 315 this, 316 link_free_crx_path)); 317 } 318 319 SandboxedUnpacker::~SandboxedUnpacker() { 320 } 321 322 bool SandboxedUnpacker::OnMessageReceived(const IPC::Message& message) { 323 bool handled = true; 324 IPC_BEGIN_MESSAGE_MAP(SandboxedUnpacker, message) 325 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_UnpackExtension_Succeeded, 326 OnUnpackExtensionSucceeded) 327 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_UnpackExtension_Failed, 328 OnUnpackExtensionFailed) 329 IPC_MESSAGE_UNHANDLED(handled = false) 330 IPC_END_MESSAGE_MAP() 331 return handled; 332 } 333 334 void SandboxedUnpacker::OnProcessCrashed(int exit_code) { 335 // Don't report crashes if they happen after we got a response. 336 if (got_response_) 337 return; 338 339 // Utility process crashed while trying to install. 340 ReportFailure( 341 UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, 342 l10n_util::GetStringFUTF16( 343 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 344 ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL")) + 345 ASCIIToUTF16(". ") + 346 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_PROCESS_CRASHED)); 347 } 348 349 void SandboxedUnpacker::StartProcessOnIOThread( 350 const base::FilePath& temp_crx_path) { 351 UtilityProcessHost* host = 352 UtilityProcessHost::Create(this, unpacker_io_task_runner_.get()); 353 // Grant the subprocess access to the entire subdir the extension file is 354 // in, so that it can unpack to that dir. 355 host->SetExposedDir(temp_crx_path.DirName()); 356 host->Send( 357 new ChromeUtilityMsg_UnpackExtension( 358 temp_crx_path, extension_id_, location_, creation_flags_)); 359 } 360 361 void SandboxedUnpacker::OnUnpackExtensionSucceeded( 362 const base::DictionaryValue& manifest) { 363 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 364 got_response_ = true; 365 366 scoped_ptr<base::DictionaryValue> final_manifest( 367 RewriteManifestFile(manifest)); 368 if (!final_manifest) 369 return; 370 371 // Create an extension object that refers to the temporary location the 372 // extension was unpacked to. We use this until the extension is finally 373 // installed. For example, the install UI shows images from inside the 374 // extension. 375 376 // Localize manifest now, so confirm UI gets correct extension name. 377 378 // TODO(rdevlin.cronin): Continue removing std::string errors and replacing 379 // with base::string16 380 std::string utf8_error; 381 if (!extension_l10n_util::LocalizeExtension(extension_root_, 382 final_manifest.get(), 383 &utf8_error)) { 384 ReportFailure( 385 COULD_NOT_LOCALIZE_EXTENSION, 386 l10n_util::GetStringFUTF16( 387 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, 388 base::UTF8ToUTF16(utf8_error))); 389 return; 390 } 391 392 extension_ = Extension::Create( 393 extension_root_, 394 location_, 395 *final_manifest, 396 Extension::REQUIRE_KEY | creation_flags_, 397 &utf8_error); 398 399 if (!extension_.get()) { 400 ReportFailure(INVALID_MANIFEST, 401 ASCIIToUTF16("Manifest is invalid: " + utf8_error)); 402 return; 403 } 404 405 SkBitmap install_icon; 406 if (!RewriteImageFiles(&install_icon)) 407 return; 408 409 if (!RewriteCatalogFiles()) 410 return; 411 412 ReportSuccess(manifest, install_icon); 413 } 414 415 void SandboxedUnpacker::OnUnpackExtensionFailed(const base::string16& error) { 416 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 417 got_response_ = true; 418 ReportFailure( 419 UNPACKER_CLIENT_FAILED, 420 l10n_util::GetStringFUTF16( 421 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, 422 error)); 423 } 424 425 bool SandboxedUnpacker::ValidateSignature() { 426 base::ScopedFILE file(base::OpenFile(crx_path_, "rb")); 427 428 if (!file.get()) { 429 // Could not open crx file for reading. 430 #if defined (OS_WIN) 431 // On windows, get the error code. 432 uint32 error_code = ::GetLastError(); 433 // TODO(skerner): Use this histogram to understand why so many 434 // windows users hit this error. crbug.com/69693 435 436 // Windows errors are unit32s, but all of likely errors are in 437 // [1, 1000]. See winerror.h for the meaning of specific values. 438 // Clip errors outside the expected range to a single extra value. 439 // If there are errors in that extra bucket, we will know to expand 440 // the range. 441 const uint32 kMaxErrorToSend = 1001; 442 error_code = std::min(error_code, kMaxErrorToSend); 443 UMA_HISTOGRAM_ENUMERATION("Extensions.ErrorCodeFromCrxOpen", 444 error_code, kMaxErrorToSend); 445 #endif 446 447 ReportFailure( 448 CRX_FILE_NOT_READABLE, 449 l10n_util::GetStringFUTF16( 450 IDS_EXTENSION_PACKAGE_ERROR_CODE, 451 ASCIIToUTF16("CRX_FILE_NOT_READABLE"))); 452 return false; 453 } 454 455 // Read and verify the header. 456 // 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 458 // code in the code base. So for now, this assumes that we're running 459 // on a little endian machine with 4 byte alignment. 460 CrxFile::Header header; 461 size_t len = fread(&header, 1, sizeof(header), file.get()); 462 if (len < sizeof(header)) { 463 // Invalid crx header 464 ReportFailure( 465 CRX_HEADER_INVALID, 466 l10n_util::GetStringFUTF16( 467 IDS_EXTENSION_PACKAGE_ERROR_CODE, 468 ASCIIToUTF16("CRX_HEADER_INVALID"))); 469 return false; 470 } 471 472 CrxFile::Error error; 473 scoped_ptr<CrxFile> crx(CrxFile::Parse(header, &error)); 474 if (!crx) { 475 switch (error) { 476 case CrxFile::kWrongMagic: 477 ReportFailure( 478 CRX_MAGIC_NUMBER_INVALID, 479 l10n_util::GetStringFUTF16( 480 IDS_EXTENSION_PACKAGE_ERROR_CODE, 481 ASCIIToUTF16("CRX_MAGIC_NUMBER_INVALID"))); 482 break; 483 case CrxFile::kInvalidVersion: 484 // Bad version numer 485 ReportFailure( 486 CRX_VERSION_NUMBER_INVALID, 487 l10n_util::GetStringFUTF16( 488 IDS_EXTENSION_PACKAGE_ERROR_CODE, 489 ASCIIToUTF16("CRX_VERSION_NUMBER_INVALID"))); 490 break; 491 case CrxFile::kInvalidKeyTooLarge: 492 case CrxFile::kInvalidSignatureTooLarge: 493 // Excessively large key or signature 494 ReportFailure( 495 CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE, 496 l10n_util::GetStringFUTF16( 497 IDS_EXTENSION_PACKAGE_ERROR_CODE, 498 ASCIIToUTF16("CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE"))); 499 break; 500 case CrxFile::kInvalidKeyTooSmall: 501 // Key length is zero 502 ReportFailure( 503 CRX_ZERO_KEY_LENGTH, 504 l10n_util::GetStringFUTF16( 505 IDS_EXTENSION_PACKAGE_ERROR_CODE, 506 ASCIIToUTF16("CRX_ZERO_KEY_LENGTH"))); 507 break; 508 case CrxFile::kInvalidSignatureTooSmall: 509 // Signature length is zero 510 ReportFailure( 511 CRX_ZERO_SIGNATURE_LENGTH, 512 l10n_util::GetStringFUTF16( 513 IDS_EXTENSION_PACKAGE_ERROR_CODE, 514 ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH"))); 515 break; 516 } 517 return false; 518 } 519 520 std::vector<uint8> key; 521 key.resize(header.key_size); 522 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); 523 if (len < header.key_size) { 524 // Invalid public key 525 ReportFailure( 526 CRX_PUBLIC_KEY_INVALID, 527 l10n_util::GetStringFUTF16( 528 IDS_EXTENSION_PACKAGE_ERROR_CODE, 529 ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID"))); 530 return false; 531 } 532 533 std::vector<uint8> signature; 534 signature.resize(header.signature_size); 535 len = fread(&signature.front(), sizeof(uint8), header.signature_size, 536 file.get()); 537 if (len < header.signature_size) { 538 // Invalid signature 539 ReportFailure( 540 CRX_SIGNATURE_INVALID, 541 l10n_util::GetStringFUTF16( 542 IDS_EXTENSION_PACKAGE_ERROR_CODE, 543 ASCIIToUTF16("CRX_SIGNATURE_INVALID"))); 544 return false; 545 } 546 547 crypto::SignatureVerifier verifier; 548 if (!verifier.VerifyInit(crx_file::kSignatureAlgorithm, 549 sizeof(crx_file::kSignatureAlgorithm), 550 &signature.front(), 551 signature.size(), 552 &key.front(), 553 key.size())) { 554 // Signature verification initialization failed. This is most likely 555 // caused by a public key in the wrong format (should encode algorithm). 556 ReportFailure( 557 CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED, 558 l10n_util::GetStringFUTF16( 559 IDS_EXTENSION_PACKAGE_ERROR_CODE, 560 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED"))); 561 return false; 562 } 563 564 unsigned char buf[1 << 12]; 565 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) 566 verifier.VerifyUpdate(buf, len); 567 568 if (!verifier.VerifyFinal()) { 569 // Signature verification failed 570 ReportFailure( 571 CRX_SIGNATURE_VERIFICATION_FAILED, 572 l10n_util::GetStringFUTF16( 573 IDS_EXTENSION_PACKAGE_ERROR_CODE, 574 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED"))); 575 return false; 576 } 577 578 std::string public_key = 579 std::string(reinterpret_cast<char*>(&key.front()), key.size()); 580 base::Base64Encode(public_key, &public_key_); 581 582 extension_id_ = crx_file::id_util::GenerateId(public_key); 583 584 return true; 585 } 586 587 void SandboxedUnpacker::ReportFailure(FailureReason reason, 588 const base::string16& error) { 589 UMA_HISTOGRAM_ENUMERATION("Extensions.SandboxUnpackFailureReason", 590 reason, NUM_FAILURE_REASONS); 591 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackFailureTime", 592 base::TimeTicks::Now() - unpack_start_time_); 593 Cleanup(); 594 client_->OnUnpackFailure(error); 595 } 596 597 void SandboxedUnpacker::ReportSuccess( 598 const base::DictionaryValue& original_manifest, 599 const SkBitmap& install_icon) { 600 UMA_HISTOGRAM_COUNTS("Extensions.SandboxUnpackSuccess", 1); 601 602 RecordSuccessfulUnpackTimeHistograms( 603 crx_path_, base::TimeTicks::Now() - unpack_start_time_); 604 605 // Client takes ownership of temporary directory and extension. 606 client_->OnUnpackSuccess( 607 temp_dir_.Take(), extension_root_, &original_manifest, extension_.get(), 608 install_icon); 609 extension_ = NULL; 610 } 611 612 base::DictionaryValue* SandboxedUnpacker::RewriteManifestFile( 613 const base::DictionaryValue& manifest) { 614 // Add the public key extracted earlier to the parsed manifest and overwrite 615 // the original manifest. We do this to ensure the manifest doesn't contain an 616 // exploitable bug that could be used to compromise the browser. 617 scoped_ptr<base::DictionaryValue> final_manifest(manifest.DeepCopy()); 618 final_manifest->SetString(manifest_keys::kPublicKey, public_key_); 619 620 std::string manifest_json; 621 JSONStringValueSerializer serializer(&manifest_json); 622 serializer.set_pretty_print(true); 623 if (!serializer.Serialize(*final_manifest)) { 624 // Error serializing manifest.json. 625 ReportFailure( 626 ERROR_SERIALIZING_MANIFEST_JSON, 627 l10n_util::GetStringFUTF16( 628 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 629 ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON"))); 630 return NULL; 631 } 632 633 base::FilePath manifest_path = 634 extension_root_.Append(kManifestFilename); 635 int size = base::checked_cast<int>(manifest_json.size()); 636 if (base::WriteFile(manifest_path, manifest_json.data(), size) != size) { 637 // Error saving manifest.json. 638 ReportFailure( 639 ERROR_SAVING_MANIFEST_JSON, 640 l10n_util::GetStringFUTF16( 641 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 642 ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON"))); 643 return NULL; 644 } 645 646 return final_manifest.release(); 647 } 648 649 bool SandboxedUnpacker::RewriteImageFiles(SkBitmap* install_icon) { 650 DecodedImages images; 651 if (!ReadImagesFromFile(temp_dir_.path(), &images)) { 652 // Couldn't read image data from disk. 653 ReportFailure( 654 COULD_NOT_READ_IMAGE_DATA_FROM_DISK, 655 l10n_util::GetStringFUTF16( 656 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 657 ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK"))); 658 return false; 659 } 660 661 // Delete any images that may be used by the browser. We're going to write 662 // out our own versions of the parsed images, and we want to make sure the 663 // originals are gone for good. 664 std::set<base::FilePath> image_paths = 665 extension_file_util::GetBrowserImagePaths(extension_.get()); 666 if (image_paths.size() != images.size()) { 667 // Decoded images don't match what's in the manifest. 668 ReportFailure( 669 DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST, 670 l10n_util::GetStringFUTF16( 671 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 672 ASCIIToUTF16("DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST"))); 673 return false; 674 } 675 676 for (std::set<base::FilePath>::iterator it = image_paths.begin(); 677 it != image_paths.end(); ++it) { 678 base::FilePath path = *it; 679 if (path.IsAbsolute() || path.ReferencesParent()) { 680 // Invalid path for browser image. 681 ReportFailure( 682 INVALID_PATH_FOR_BROWSER_IMAGE, 683 l10n_util::GetStringFUTF16( 684 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 685 ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE"))); 686 return false; 687 } 688 if (!base::DeleteFile(extension_root_.Append(path), false)) { 689 // Error removing old image file. 690 ReportFailure( 691 ERROR_REMOVING_OLD_IMAGE_FILE, 692 l10n_util::GetStringFUTF16( 693 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 694 ASCIIToUTF16("ERROR_REMOVING_OLD_IMAGE_FILE"))); 695 return false; 696 } 697 } 698 699 const std::string& install_icon_path = 700 IconsInfo::GetIcons(extension_.get()).Get( 701 extension_misc::EXTENSION_ICON_LARGE, ExtensionIconSet::MATCH_BIGGER); 702 703 // Write our parsed images back to disk as well. 704 for (size_t i = 0; i < images.size(); ++i) { 705 if (BrowserThread::GetBlockingPool()->IsShutdownInProgress()) { 706 // Abort package installation if shutdown was initiated, crbug.com/235525 707 ReportFailure( 708 ABORTED_DUE_TO_SHUTDOWN, 709 l10n_util::GetStringFUTF16( 710 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 711 ASCIIToUTF16("ABORTED_DUE_TO_SHUTDOWN"))); 712 return false; 713 } 714 715 const SkBitmap& image = images[i].a; 716 base::FilePath path_suffix = images[i].b; 717 if (path_suffix.MaybeAsASCII() == install_icon_path) 718 *install_icon = image; 719 720 if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { 721 // Invalid path for bitmap image. 722 ReportFailure( 723 INVALID_PATH_FOR_BITMAP_IMAGE, 724 l10n_util::GetStringFUTF16( 725 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 726 ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE"))); 727 return false; 728 } 729 base::FilePath path = extension_root_.Append(path_suffix); 730 731 std::vector<unsigned char> image_data; 732 // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even 733 // though they may originally be .jpg, etc. Figure something out. 734 // http://code.google.com/p/chromium/issues/detail?id=12459 735 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { 736 // Error re-encoding theme image. 737 ReportFailure( 738 ERROR_RE_ENCODING_THEME_IMAGE, 739 l10n_util::GetStringFUTF16( 740 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 741 ASCIIToUTF16("ERROR_RE_ENCODING_THEME_IMAGE"))); 742 return false; 743 } 744 745 // Note: we're overwriting existing files that the utility process wrote, 746 // so we can be sure the directory exists. 747 const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]); 748 int size = base::checked_cast<int>(image_data.size()); 749 if (base::WriteFile(path, image_data_ptr, size) != size) { 750 // Error saving theme image. 751 ReportFailure( 752 ERROR_SAVING_THEME_IMAGE, 753 l10n_util::GetStringFUTF16( 754 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 755 ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE"))); 756 return false; 757 } 758 } 759 760 return true; 761 } 762 763 bool SandboxedUnpacker::RewriteCatalogFiles() { 764 base::DictionaryValue catalogs; 765 if (!ReadMessageCatalogsFromFile(temp_dir_.path(), &catalogs)) { 766 // Could not read catalog data from disk. 767 ReportFailure( 768 COULD_NOT_READ_CATALOG_DATA_FROM_DISK, 769 l10n_util::GetStringFUTF16( 770 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 771 ASCIIToUTF16("COULD_NOT_READ_CATALOG_DATA_FROM_DISK"))); 772 return false; 773 } 774 775 // Write our parsed catalogs back to disk. 776 for (base::DictionaryValue::Iterator it(catalogs); 777 !it.IsAtEnd(); it.Advance()) { 778 const base::DictionaryValue* catalog = NULL; 779 if (!it.value().GetAsDictionary(&catalog)) { 780 // Invalid catalog data. 781 ReportFailure( 782 INVALID_CATALOG_DATA, 783 l10n_util::GetStringFUTF16( 784 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 785 ASCIIToUTF16("INVALID_CATALOG_DATA"))); 786 return false; 787 } 788 789 base::FilePath relative_path = base::FilePath::FromUTF8Unsafe(it.key()); 790 relative_path = relative_path.Append(kMessagesFilename); 791 if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) { 792 // Invalid path for catalog. 793 ReportFailure( 794 INVALID_PATH_FOR_CATALOG, 795 l10n_util::GetStringFUTF16( 796 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 797 ASCIIToUTF16("INVALID_PATH_FOR_CATALOG"))); 798 return false; 799 } 800 base::FilePath path = extension_root_.Append(relative_path); 801 802 std::string catalog_json; 803 JSONStringValueSerializer serializer(&catalog_json); 804 serializer.set_pretty_print(true); 805 if (!serializer.Serialize(*catalog)) { 806 // Error serializing catalog. 807 ReportFailure( 808 ERROR_SERIALIZING_CATALOG, 809 l10n_util::GetStringFUTF16( 810 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 811 ASCIIToUTF16("ERROR_SERIALIZING_CATALOG"))); 812 return false; 813 } 814 815 // Note: we're overwriting existing files that the utility process read, 816 // so we can be sure the directory exists. 817 int size = base::checked_cast<int>(catalog_json.size()); 818 if (base::WriteFile(path, catalog_json.c_str(), size) != size) { 819 // Error saving catalog. 820 ReportFailure( 821 ERROR_SAVING_CATALOG, 822 l10n_util::GetStringFUTF16( 823 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 824 ASCIIToUTF16("ERROR_SAVING_CATALOG"))); 825 return false; 826 } 827 } 828 829 return true; 830 } 831 832 void SandboxedUnpacker::Cleanup() { 833 DCHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 834 if (!temp_dir_.Delete()) { 835 LOG(WARNING) << "Can not delete temp directory at " 836 << temp_dir_.path().value(); 837 } 838 } 839 840 } // namespace extensions 841