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 "extensions/browser/sandboxed_unpacker.h" | 5 #include "extensions/browser/sandboxed_unpacker.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <set> | 10 #include <set> |
11 #include <tuple> | 11 #include <tuple> |
12 | 12 |
13 #include "base/bind.h" | 13 #include "base/bind.h" |
14 #include "base/command_line.h" | 14 #include "base/command_line.h" |
15 #include "base/files/file_util.h" | 15 #include "base/files/file_util.h" |
16 #include "base/json/json_string_value_serializer.h" | 16 #include "base/json/json_string_value_serializer.h" |
17 #include "base/message_loop/message_loop.h" | |
18 #include "base/metrics/histogram_macros.h" | 17 #include "base/metrics/histogram_macros.h" |
19 #include "base/numerics/safe_conversions.h" | |
20 #include "base/path_service.h" | 18 #include "base/path_service.h" |
21 #include "base/sequenced_task_runner.h" | 19 #include "base/sequenced_task_runner.h" |
22 #include "base/strings/string_number_conversions.h" | |
23 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
24 #include "base/threading/sequenced_worker_pool.h" | |
25 #include "build/build_config.h" | 21 #include "build/build_config.h" |
26 #include "components/crx_file/crx_file.h" | 22 #include "components/crx_file/crx_file.h" |
27 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
28 #include "content/public/browser/utility_process_host.h" | |
29 #include "content/public/common/common_param_traits.h" | |
30 #include "extensions/common/constants.h" | 24 #include "extensions/common/constants.h" |
31 #include "extensions/common/extension.h" | 25 #include "extensions/common/extension.h" |
32 #include "extensions/common/extension_l10n_util.h" | 26 #include "extensions/common/extension_l10n_util.h" |
33 #include "extensions/common/extension_utility_messages.h" | 27 #include "extensions/common/extension_utility_messages.h" |
28 #include "extensions/common/extension_utility_types.h" | |
34 #include "extensions/common/extensions_client.h" | 29 #include "extensions/common/extensions_client.h" |
35 #include "extensions/common/file_util.h" | 30 #include "extensions/common/file_util.h" |
36 #include "extensions/common/manifest_constants.h" | 31 #include "extensions/common/manifest_constants.h" |
37 #include "extensions/common/manifest_handlers/icons_handler.h" | 32 #include "extensions/common/manifest_handlers/icons_handler.h" |
38 #include "extensions/common/switches.h" | 33 #include "extensions/common/switches.h" |
39 #include "grit/extensions_strings.h" | 34 #include "grit/extensions_strings.h" |
40 #include "third_party/skia/include/core/SkBitmap.h" | 35 #include "third_party/skia/include/core/SkBitmap.h" |
41 #include "ui/base/l10n/l10n_util.h" | 36 #include "ui/base/l10n/l10n_util.h" |
42 #include "ui/gfx/codec/png_codec.h" | 37 #include "ui/gfx/codec/png_codec.h" |
43 | 38 |
44 using base::ASCIIToUTF16; | 39 using base::ASCIIToUTF16; |
45 using content::BrowserThread; | 40 using content::BrowserThread; |
46 using content::UtilityProcessHost; | |
47 using crx_file::CrxFile; | 41 using crx_file::CrxFile; |
48 | 42 |
49 // The following macro makes histograms that record the length of paths | 43 // The following macro makes histograms that record the length of paths |
50 // in this file much easier to read. | 44 // in this file much easier to read. |
51 // Windows has a short max path length. If the path length to a | 45 // Windows has a short max path length. If the path length to a |
52 // file being unpacked from a CRX exceeds the max length, we might | 46 // file being unpacked from a CRX exceeds the max length, we might |
53 // fail to install. To see if this is happening, see how long the | 47 // fail to install. To see if this is happening, see how long the |
54 // path to the temp unpack directory is. See crbug.com/69693 . | 48 // path to the temp unpack directory is. See crbug.com/69693 . |
55 #define PATH_LENGTH_HISTOGRAM(name, path) \ | 49 #define PATH_LENGTH_HISTOGRAM(name, path) \ |
56 UMA_HISTOGRAM_CUSTOM_COUNTS(name, path.value().length(), 1, 500, 100) | 50 UMA_HISTOGRAM_CUSTOM_COUNTS(name, path.value().length(), 1, 500, 100) |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
217 } | 211 } |
218 | 212 |
219 SandboxedUnpacker::SandboxedUnpacker( | 213 SandboxedUnpacker::SandboxedUnpacker( |
220 Manifest::Location location, | 214 Manifest::Location location, |
221 int creation_flags, | 215 int creation_flags, |
222 const base::FilePath& extensions_dir, | 216 const base::FilePath& extensions_dir, |
223 const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner, | 217 const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner, |
224 SandboxedUnpackerClient* client) | 218 SandboxedUnpackerClient* client) |
225 : client_(client), | 219 : client_(client), |
226 extensions_dir_(extensions_dir), | 220 extensions_dir_(extensions_dir), |
227 got_response_(false), | |
228 location_(location), | 221 location_(location), |
229 creation_flags_(creation_flags), | 222 creation_flags_(creation_flags), |
230 unpacker_io_task_runner_(unpacker_io_task_runner), | 223 unpacker_io_task_runner_(unpacker_io_task_runner) {} |
231 utility_wrapper_(new UtilityHostWrapper) {} | |
232 | 224 |
233 bool SandboxedUnpacker::CreateTempDirectory() { | 225 bool SandboxedUnpacker::CreateTempDirectory() { |
234 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); | 226 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); |
235 | 227 |
236 base::FilePath temp_dir; | 228 base::FilePath temp_dir; |
237 if (!FindWritableTempLocation(extensions_dir_, &temp_dir)) { | 229 if (!FindWritableTempLocation(extensions_dir_, &temp_dir)) { |
238 ReportFailure(COULD_NOT_GET_TEMP_DIRECTORY, | 230 ReportFailure(COULD_NOT_GET_TEMP_DIRECTORY, |
239 l10n_util::GetStringFUTF16( | 231 l10n_util::GetStringFUTF16( |
240 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 232 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
241 ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY"))); | 233 ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY"))); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
306 LOG(ERROR) << "Could not get the normalized path of " | 298 LOG(ERROR) << "Could not get the normalized path of " |
307 << temp_crx_path.value(); | 299 << temp_crx_path.value(); |
308 ReportFailure(COULD_NOT_GET_SANDBOX_FRIENDLY_PATH, | 300 ReportFailure(COULD_NOT_GET_SANDBOX_FRIENDLY_PATH, |
309 l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED)); | 301 l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED)); |
310 return; | 302 return; |
311 } | 303 } |
312 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackLinkFreeCrxPathLength", | 304 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackLinkFreeCrxPathLength", |
313 link_free_crx_path); | 305 link_free_crx_path); |
314 | 306 |
315 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 307 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
316 base::Bind(&SandboxedUnpacker::StartUnzipOnIOThread, | 308 base::Bind(&SandboxedUnpacker::UnzipOnIOThread, this, |
317 this, link_free_crx_path)); | 309 link_free_crx_path)); |
318 } | 310 } |
319 | 311 |
320 void SandboxedUnpacker::StartWithDirectory(const std::string& extension_id, | 312 void SandboxedUnpacker::StartWithDirectory(const std::string& extension_id, |
321 const std::string& public_key, | 313 const std::string& public_key, |
322 const base::FilePath& directory) { | 314 const base::FilePath& directory) { |
323 extension_id_ = extension_id; | 315 extension_id_ = extension_id; |
324 public_key_ = public_key; | 316 public_key_ = public_key; |
325 if (!CreateTempDirectory()) | 317 if (!CreateTempDirectory()) |
326 return; // ReportFailure() already called. | 318 return; // ReportFailure() already called. |
327 | 319 |
328 extension_root_ = temp_dir_.GetPath().AppendASCII(kTempExtensionName); | 320 extension_root_ = temp_dir_.GetPath().AppendASCII(kTempExtensionName); |
329 | 321 |
330 if (!base::Move(directory, extension_root_)) { | 322 if (!base::Move(directory, extension_root_)) { |
331 LOG(ERROR) << "Could not move " << directory.value() << " to " | 323 LOG(ERROR) << "Could not move " << directory.value() << " to " |
332 << extension_root_.value(); | 324 << extension_root_.value(); |
333 ReportFailure( | 325 ReportFailure( |
334 DIRECTORY_MOVE_FAILED, | 326 DIRECTORY_MOVE_FAILED, |
335 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 327 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
336 ASCIIToUTF16("DIRECTORY_MOVE_FAILED"))); | 328 ASCIIToUTF16("DIRECTORY_MOVE_FAILED"))); |
337 return; | 329 return; |
338 } | 330 } |
339 | 331 |
340 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 332 BrowserThread::PostTask( |
341 base::Bind(&SandboxedUnpacker::StartUnpackOnIOThread, | 333 BrowserThread::IO, FROM_HERE, |
342 this, extension_root_)); | 334 base::Bind(&SandboxedUnpacker::UnpackOnIOThread, this, extension_root_)); |
343 } | 335 } |
344 | 336 |
345 SandboxedUnpacker::~SandboxedUnpacker() { | 337 SandboxedUnpacker::~SandboxedUnpacker() { |
346 // To avoid blocking shutdown, don't delete temporary directory here if it | 338 // To avoid blocking shutdown, don't delete temporary directory here if it |
347 // hasn't been cleaned up or passed on to another owner yet. | 339 // hasn't been cleaned up or passed on to another owner yet. |
348 temp_dir_.Take(); | 340 temp_dir_.Take(); |
349 } | 341 } |
350 | 342 |
351 bool SandboxedUnpacker::OnMessageReceived(const IPC::Message& message) { | 343 void SandboxedUnpacker::StartUtilityProcess(const base::FilePath& dir) { |
352 bool handled = true; | 344 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
353 IPC_BEGIN_MESSAGE_MAP(SandboxedUnpacker, message) | 345 DCHECK(!dir.empty()); |
354 IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnzipToDir_Succeeded, | 346 |
355 OnUnzipToDirSucceeded) | 347 if (utility_process_mojo_client_) |
Devlin
2017/02/14 17:24:59
Should this happen? It looks like we're clearing
Noel Gordon
2017/02/15 17:28:08
Yes it will happen. We clear it on failures [1],
| |
356 IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnzipToDir_Failed, | 348 return; |
357 OnUnzipToDirFailed) | 349 |
358 IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnpackExtension_Succeeded, | 350 utility_process_mojo_client_ = base::MakeUnique< |
359 OnUnpackExtensionSucceeded) | 351 content::UtilityProcessMojoClient<extensions::mojom::ExtensionUnpacker>>( |
360 IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnpackExtension_Failed, | 352 l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME)); |
361 OnUnpackExtensionFailed) | 353 utility_process_mojo_client_->set_error_callback( |
362 IPC_MESSAGE_UNHANDLED(handled = false) | 354 base::Bind(&SandboxedUnpacker::UtilityProcessCrashed, this)); |
363 IPC_END_MESSAGE_MAP() | 355 utility_process_mojo_client_->set_exposed_directory(dir); |
364 return handled; | 356 |
357 utility_process_mojo_client_->Start(); | |
365 } | 358 } |
366 | 359 |
367 void SandboxedUnpacker::OnProcessCrashed(int exit_code) { | 360 void SandboxedUnpacker::UtilityProcessCrashed() { |
368 // Don't report crashes if they happen after we got a response. | 361 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
369 if (got_response_) | |
370 return; | |
371 | 362 |
372 // Utility process crashed while trying to install. | 363 utility_process_mojo_client_.reset(); |
364 | |
373 ReportFailure( | 365 ReportFailure( |
374 UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, | 366 UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, |
375 l10n_util::GetStringFUTF16( | 367 l10n_util::GetStringFUTF16( |
376 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 368 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
377 ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL")) + | 369 ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL")) + |
378 ASCIIToUTF16(". ") + | 370 ASCIIToUTF16(". ") + |
379 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_PROCESS_CRASHED)); | 371 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_PROCESS_CRASHED)); |
380 } | 372 } |
381 | 373 |
382 void SandboxedUnpacker::StartUnzipOnIOThread(const base::FilePath& crx_path) { | 374 void SandboxedUnpacker::UnzipOnIOThread(const base::FilePath& crx_path) { |
383 if (!utility_wrapper_->StartIfNeeded(temp_dir_.GetPath(), this, | 375 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
384 unpacker_io_task_runner_)) { | 376 |
385 ReportFailure( | 377 StartUtilityProcess(temp_dir_.GetPath()); |
386 COULD_NOT_START_UTILITY_PROCESS, | 378 |
387 l10n_util::GetStringFUTF16( | |
388 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | |
389 FailureReasonToString16(COULD_NOT_START_UTILITY_PROCESS))); | |
390 return; | |
391 } | |
392 DCHECK(crx_path.DirName() == temp_dir_.GetPath()); | 379 DCHECK(crx_path.DirName() == temp_dir_.GetPath()); |
393 base::FilePath unzipped_dir = | 380 base::FilePath unzipped_dir = |
394 crx_path.DirName().AppendASCII(kTempExtensionName); | 381 crx_path.DirName().AppendASCII(kTempExtensionName); |
395 utility_wrapper_->host()->Send( | 382 |
396 new ExtensionUtilityMsg_UnzipToDir(crx_path, unzipped_dir)); | 383 utility_process_mojo_client_->service()->Unzip( |
384 crx_path, unzipped_dir, | |
385 base::Bind(&SandboxedUnpacker::UnzipDone, this, unzipped_dir)); | |
397 } | 386 } |
398 | 387 |
399 void SandboxedUnpacker::StartUnpackOnIOThread( | 388 void SandboxedUnpacker::UnzipDone(const base::FilePath& directory, |
400 const base::FilePath& directory_path) { | 389 bool success) { |
401 if (!utility_wrapper_->StartIfNeeded(temp_dir_.GetPath(), this, | 390 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
402 unpacker_io_task_runner_)) { | 391 |
403 ReportFailure( | 392 if (!success) { |
404 COULD_NOT_START_UTILITY_PROCESS, | 393 utility_process_mojo_client_.reset(); |
405 l10n_util::GetStringFUTF16( | 394 ReportFailure(UNZIP_FAILED, |
406 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 395 l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR)); |
407 FailureReasonToString16(COULD_NOT_START_UTILITY_PROCESS))); | |
408 return; | 396 return; |
409 } | 397 } |
410 DCHECK(directory_path.DirName() == temp_dir_.GetPath()); | 398 |
411 utility_wrapper_->host()->Send(new ExtensionUtilityMsg_UnpackExtension( | 399 BrowserThread::PostTask( |
412 directory_path, extension_id_, location_, creation_flags_)); | 400 BrowserThread::IO, FROM_HERE, |
401 base::Bind(&SandboxedUnpacker::UnpackOnIOThread, this, directory)); | |
413 } | 402 } |
414 | 403 |
415 void SandboxedUnpacker::OnUnzipToDirSucceeded(const base::FilePath& directory) { | 404 void SandboxedUnpacker::UnpackOnIOThread(const base::FilePath& directory) { |
416 BrowserThread::PostTask( | 405 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
417 BrowserThread::IO, FROM_HERE, | 406 |
418 base::Bind(&SandboxedUnpacker::StartUnpackOnIOThread, this, directory)); | 407 StartUtilityProcess(temp_dir_.GetPath()); |
408 | |
409 DCHECK(directory.DirName() == temp_dir_.GetPath()); | |
410 | |
411 utility_process_mojo_client_->service()->Unpack( | |
412 directory, extension_id_, location_, creation_flags_, | |
413 base::Bind(&SandboxedUnpacker::UnpackDone, this)); | |
419 } | 414 } |
420 | 415 |
421 void SandboxedUnpacker::OnUnzipToDirFailed(const std::string& error) { | 416 void SandboxedUnpacker::UnpackDone( |
422 got_response_ = true; | 417 const base::string16& error, |
423 utility_wrapper_ = nullptr; | 418 std::unique_ptr<base::DictionaryValue> manifest) { |
424 ReportFailure(UNZIP_FAILED, | 419 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
425 l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR)); | 420 |
421 utility_process_mojo_client_.reset(); | |
422 | |
423 if (!error.empty()) { | |
424 unpacker_io_task_runner_->PostTask( | |
425 FROM_HERE, | |
426 base::Bind(&SandboxedUnpacker::UnpackExtensionFailed, this, error)); | |
427 return; | |
428 } | |
429 | |
430 unpacker_io_task_runner_->PostTask( | |
431 FROM_HERE, base::Bind(&SandboxedUnpacker::UnpackExtensionSucceeded, this, | |
432 base::Passed(&manifest))); | |
426 } | 433 } |
427 | 434 |
428 void SandboxedUnpacker::OnUnpackExtensionSucceeded( | 435 void SandboxedUnpacker::UnpackExtensionSucceeded( |
429 const base::DictionaryValue& manifest) { | 436 std::unique_ptr<base::DictionaryValue> manifest) { |
430 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); | 437 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); |
431 got_response_ = true; | |
432 utility_wrapper_ = nullptr; | |
433 | 438 |
434 std::unique_ptr<base::DictionaryValue> final_manifest( | 439 std::unique_ptr<base::DictionaryValue> final_manifest( |
435 RewriteManifestFile(manifest)); | 440 RewriteManifestFile(*manifest.get())); |
Devlin
2017/02/14 17:24:59
*foo.get() is redundant. Prefer just *foo.
Noel Gordon
2017/02/15 17:28:08
Done.
| |
436 if (!final_manifest) | 441 if (!final_manifest) |
437 return; | 442 return; |
438 | 443 |
439 // Create an extension object that refers to the temporary location the | 444 // Create an extension object that refers to the temporary location the |
440 // extension was unpacked to. We use this until the extension is finally | 445 // extension was unpacked to. We use this until the extension is finally |
441 // installed. For example, the install UI shows images from inside the | 446 // installed. For example, the install UI shows images from inside the |
442 // extension. | 447 // extension. |
443 | 448 |
444 // Localize manifest now, so confirm UI gets correct extension name. | 449 // Localize manifest now, so confirm UI gets correct extension name. |
445 | 450 |
(...skipping 19 matching lines...) Expand all Loading... | |
465 return; | 470 return; |
466 } | 471 } |
467 | 472 |
468 SkBitmap install_icon; | 473 SkBitmap install_icon; |
469 if (!RewriteImageFiles(&install_icon)) | 474 if (!RewriteImageFiles(&install_icon)) |
470 return; | 475 return; |
471 | 476 |
472 if (!RewriteCatalogFiles()) | 477 if (!RewriteCatalogFiles()) |
473 return; | 478 return; |
474 | 479 |
475 ReportSuccess(manifest, install_icon); | 480 ReportSuccess(std::move(manifest), install_icon); |
476 } | 481 } |
477 | 482 |
478 void SandboxedUnpacker::OnUnpackExtensionFailed(const base::string16& error) { | 483 void SandboxedUnpacker::UnpackExtensionFailed(const base::string16& error) { |
479 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); | 484 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); |
480 got_response_ = true; | 485 |
481 utility_wrapper_ = nullptr; | |
482 ReportFailure( | 486 ReportFailure( |
483 UNPACKER_CLIENT_FAILED, | 487 UNPACKER_CLIENT_FAILED, |
484 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error)); | 488 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error)); |
485 } | 489 } |
486 | 490 |
487 base::string16 SandboxedUnpacker::FailureReasonToString16( | 491 base::string16 SandboxedUnpacker::FailureReasonToString16( |
488 FailureReason reason) { | 492 FailureReason reason) { |
489 switch (reason) { | 493 switch (reason) { |
490 case COULD_NOT_GET_TEMP_DIRECTORY: | 494 case COULD_NOT_GET_TEMP_DIRECTORY: |
491 return ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY"); | 495 return ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY"); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
560 case ERROR_SAVING_CATALOG: | 564 case ERROR_SAVING_CATALOG: |
561 return ASCIIToUTF16("ERROR_SAVING_CATALOG"); | 565 return ASCIIToUTF16("ERROR_SAVING_CATALOG"); |
562 | 566 |
563 case CRX_HASH_VERIFICATION_FAILED: | 567 case CRX_HASH_VERIFICATION_FAILED: |
564 return ASCIIToUTF16("CRX_HASH_VERIFICATION_FAILED"); | 568 return ASCIIToUTF16("CRX_HASH_VERIFICATION_FAILED"); |
565 | 569 |
566 case UNZIP_FAILED: | 570 case UNZIP_FAILED: |
567 return ASCIIToUTF16("UNZIP_FAILED"); | 571 return ASCIIToUTF16("UNZIP_FAILED"); |
568 case DIRECTORY_MOVE_FAILED: | 572 case DIRECTORY_MOVE_FAILED: |
569 return ASCIIToUTF16("DIRECTORY_MOVE_FAILED"); | 573 return ASCIIToUTF16("DIRECTORY_MOVE_FAILED"); |
570 case COULD_NOT_START_UTILITY_PROCESS: | |
571 return ASCIIToUTF16("COULD_NOT_START_UTILITY_PROCESS"); | |
572 | 574 |
573 case NUM_FAILURE_REASONS: | 575 case NUM_FAILURE_REASONS: |
574 NOTREACHED(); | 576 NOTREACHED(); |
575 return base::string16(); | 577 return base::string16(); |
576 } | 578 } |
579 | |
577 NOTREACHED(); | 580 NOTREACHED(); |
578 return base::string16(); | 581 return base::string16(); |
579 } | 582 } |
580 | 583 |
581 void SandboxedUnpacker::FailWithPackageError(FailureReason reason) { | 584 void SandboxedUnpacker::FailWithPackageError(FailureReason reason) { |
582 ReportFailure(reason, | 585 ReportFailure(reason, |
583 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_CODE, | 586 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_CODE, |
584 FailureReasonToString16(reason))); | 587 FailureReasonToString16(reason))); |
585 } | 588 } |
586 | 589 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
636 CHECK(!expected_hash.empty()); | 639 CHECK(!expected_hash.empty()); |
637 UMA_HISTOGRAM_BOOLEAN("Extensions.SandboxUnpackHashCheck", false); | 640 UMA_HISTOGRAM_BOOLEAN("Extensions.SandboxUnpackHashCheck", false); |
638 FailWithPackageError(CRX_HASH_VERIFICATION_FAILED); | 641 FailWithPackageError(CRX_HASH_VERIFICATION_FAILED); |
639 break; | 642 break; |
640 } | 643 } |
641 return false; | 644 return false; |
642 } | 645 } |
643 | 646 |
644 void SandboxedUnpacker::ReportFailure(FailureReason reason, | 647 void SandboxedUnpacker::ReportFailure(FailureReason reason, |
645 const base::string16& error) { | 648 const base::string16& error) { |
646 utility_wrapper_ = nullptr; | |
647 UMA_HISTOGRAM_ENUMERATION("Extensions.SandboxUnpackFailureReason", reason, | 649 UMA_HISTOGRAM_ENUMERATION("Extensions.SandboxUnpackFailureReason", reason, |
648 NUM_FAILURE_REASONS); | 650 NUM_FAILURE_REASONS); |
649 if (!crx_unpack_start_time_.is_null()) | 651 if (!crx_unpack_start_time_.is_null()) |
650 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackFailureTime", | 652 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackFailureTime", |
651 base::TimeTicks::Now() - crx_unpack_start_time_); | 653 base::TimeTicks::Now() - crx_unpack_start_time_); |
652 Cleanup(); | 654 Cleanup(); |
653 | 655 |
654 CrxInstallError error_info(reason == CRX_HASH_VERIFICATION_FAILED | 656 CrxInstallError error_info(reason == CRX_HASH_VERIFICATION_FAILED |
655 ? CrxInstallError::ERROR_HASH_MISMATCH | 657 ? CrxInstallError::ERROR_HASH_MISMATCH |
656 : CrxInstallError::ERROR_OTHER, | 658 : CrxInstallError::ERROR_OTHER, |
657 error); | 659 error); |
658 | 660 |
659 client_->OnUnpackFailure(error_info); | 661 client_->OnUnpackFailure(error_info); |
660 } | 662 } |
661 | 663 |
662 void SandboxedUnpacker::ReportSuccess( | 664 void SandboxedUnpacker::ReportSuccess( |
663 const base::DictionaryValue& original_manifest, | 665 std::unique_ptr<base::DictionaryValue> original_manifest, |
664 const SkBitmap& install_icon) { | 666 const SkBitmap& install_icon) { |
665 utility_wrapper_ = nullptr; | |
666 UMA_HISTOGRAM_COUNTS("Extensions.SandboxUnpackSuccess", 1); | 667 UMA_HISTOGRAM_COUNTS("Extensions.SandboxUnpackSuccess", 1); |
667 | 668 |
668 if (!crx_unpack_start_time_.is_null()) | 669 if (!crx_unpack_start_time_.is_null()) |
669 RecordSuccessfulUnpackTimeHistograms( | 670 RecordSuccessfulUnpackTimeHistograms( |
670 crx_path_for_histograms_, | 671 crx_path_for_histograms_, |
671 base::TimeTicks::Now() - crx_unpack_start_time_); | 672 base::TimeTicks::Now() - crx_unpack_start_time_); |
672 DCHECK(!temp_dir_.GetPath().empty()); | 673 DCHECK(!temp_dir_.GetPath().empty()); |
673 | 674 |
674 // Client takes ownership of temporary directory and extension. | 675 // Client takes ownership of temporary directory and extension. |
675 client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_, | 676 client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_, |
676 &original_manifest, extension_.get(), install_icon); | 677 original_manifest.get(), extension_.get(), |
Noel Gordon
2017/02/15 17:28:08
Perhaps client_->OnUnpackSuccess could take owners
| |
678 install_icon); | |
677 extension_ = NULL; | 679 extension_ = NULL; |
678 } | 680 } |
679 | 681 |
680 base::DictionaryValue* SandboxedUnpacker::RewriteManifestFile( | 682 base::DictionaryValue* SandboxedUnpacker::RewriteManifestFile( |
681 const base::DictionaryValue& manifest) { | 683 const base::DictionaryValue& manifest) { |
682 // Add the public key extracted earlier to the parsed manifest and overwrite | 684 // Add the public key extracted earlier to the parsed manifest and overwrite |
683 // the original manifest. We do this to ensure the manifest doesn't contain an | 685 // the original manifest. We do this to ensure the manifest doesn't contain an |
684 // exploitable bug that could be used to compromise the browser. | 686 // exploitable bug that could be used to compromise the browser. |
685 DCHECK(!public_key_.empty()); | 687 DCHECK(!public_key_.empty()); |
686 std::unique_ptr<base::DictionaryValue> final_manifest(manifest.DeepCopy()); | 688 std::unique_ptr<base::DictionaryValue> final_manifest(manifest.DeepCopy()); |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
886 } | 888 } |
887 | 889 |
888 void SandboxedUnpacker::Cleanup() { | 890 void SandboxedUnpacker::Cleanup() { |
889 DCHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); | 891 DCHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); |
890 if (!temp_dir_.Delete()) { | 892 if (!temp_dir_.Delete()) { |
891 LOG(WARNING) << "Can not delete temp directory at " | 893 LOG(WARNING) << "Can not delete temp directory at " |
892 << temp_dir_.GetPath().value(); | 894 << temp_dir_.GetPath().value(); |
893 } | 895 } |
894 } | 896 } |
895 | 897 |
896 SandboxedUnpacker::UtilityHostWrapper::UtilityHostWrapper() {} | |
897 | |
898 bool SandboxedUnpacker::UtilityHostWrapper::StartIfNeeded( | |
899 const base::FilePath& exposed_dir, | |
900 const scoped_refptr<UtilityProcessHostClient>& client, | |
901 const scoped_refptr<base::SequencedTaskRunner>& client_task_runner) { | |
902 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
903 if (!utility_host_) { | |
904 utility_host_ = | |
905 UtilityProcessHost::Create(client, client_task_runner)->AsWeakPtr(); | |
906 utility_host_->SetName( | |
907 l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME)); | |
908 | |
909 // Grant the subprocess access to our temp dir so it can write out files. | |
910 DCHECK(!exposed_dir.empty()); | |
911 utility_host_->SetExposedDir(exposed_dir); | |
912 if (!utility_host_->StartBatchMode()) { | |
913 utility_host_.reset(); | |
914 return false; | |
915 } | |
916 } | |
917 return true; | |
918 } | |
919 | |
920 content::UtilityProcessHost* SandboxedUnpacker::UtilityHostWrapper::host() | |
921 const { | |
922 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
923 return utility_host_.get(); | |
924 } | |
925 | |
926 SandboxedUnpacker::UtilityHostWrapper::~UtilityHostWrapper() { | |
927 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
928 if (utility_host_) { | |
929 utility_host_->EndBatchMode(); | |
930 utility_host_.reset(); | |
931 } | |
932 } | |
933 | |
934 } // namespace extensions | 898 } // namespace extensions |
OLD | NEW |