| Index: extensions/browser/sandboxed_unpacker.cc
|
| diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
|
| index 043dcd629576231049b486cd8baf1ccf59e29a88..5f36c51e44bff3140696ad2143c6f475c5777275 100644
|
| --- a/extensions/browser/sandboxed_unpacker.cc
|
| +++ b/extensions/browser/sandboxed_unpacker.cc
|
| @@ -14,23 +14,19 @@
|
| #include "base/command_line.h"
|
| #include "base/files/file_util.h"
|
| #include "base/json/json_string_value_serializer.h"
|
| -#include "base/message_loop/message_loop.h"
|
| #include "base/metrics/histogram_macros.h"
|
| -#include "base/numerics/safe_conversions.h"
|
| #include "base/path_service.h"
|
| #include "base/sequenced_task_runner.h"
|
| -#include "base/strings/string_number_conversions.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/threading/sequenced_worker_pool.h"
|
| #include "build/build_config.h"
|
| #include "components/crx_file/crx_file.h"
|
| #include "content/public/browser/browser_thread.h"
|
| -#include "content/public/browser/utility_process_host.h"
|
| -#include "content/public/common/common_param_traits.h"
|
| #include "extensions/common/constants.h"
|
| #include "extensions/common/extension.h"
|
| #include "extensions/common/extension_l10n_util.h"
|
| -#include "extensions/common/extension_utility_messages.h"
|
| +#include "extensions/common/extension_unpacker.mojom.h"
|
| +#include "extensions/common/extension_utility_types.h"
|
| #include "extensions/common/extensions_client.h"
|
| #include "extensions/common/file_util.h"
|
| #include "extensions/common/manifest_constants.h"
|
| @@ -43,7 +39,6 @@
|
|
|
| using base::ASCIIToUTF16;
|
| using content::BrowserThread;
|
| -using content::UtilityProcessHost;
|
| using crx_file::CrxFile;
|
|
|
| // The following macro makes histograms that record the length of paths
|
| @@ -129,21 +124,25 @@ bool VerifyJunctionFreeLocation(base::FilePath* temp_dir) {
|
| LOG(ERROR) << temp_dir->value() << " is not writable";
|
| return false;
|
| }
|
| +
|
| // NormalizeFilePath requires a non-empty file, so write some data.
|
| // If you change the exit points of this function please make sure all
|
| // exit points delete this temp file!
|
| - if (base::WriteFile(temp_file, ".", 1) != 1)
|
| + if (base::WriteFile(temp_file, ".", 1) != 1) {
|
| + base::DeleteFile(temp_file, false);
|
| return false;
|
| + }
|
|
|
| base::FilePath normalized_temp_file;
|
| bool normalized = base::NormalizeFilePath(temp_file, &normalized_temp_file);
|
| if (!normalized) {
|
| - // If |temp_file| contains a link, the sandbox will block al file system
|
| - // operations, and the install will fail.
|
| + // If |temp_file| contains a link, the sandbox will block all file
|
| + // system operations, and the install will fail.
|
| LOG(ERROR) << temp_dir->value() << " seem to be on remote drive.";
|
| } else {
|
| *temp_dir = normalized_temp_file.DirName();
|
| }
|
| +
|
| // Clean up the temp file.
|
| base::DeleteFile(temp_file, false);
|
|
|
| @@ -224,11 +223,9 @@ SandboxedUnpacker::SandboxedUnpacker(
|
| SandboxedUnpackerClient* client)
|
| : client_(client),
|
| extensions_dir_(extensions_dir),
|
| - got_response_(false),
|
| location_(location),
|
| creation_flags_(creation_flags),
|
| - unpacker_io_task_runner_(unpacker_io_task_runner),
|
| - utility_wrapper_(new UtilityHostWrapper) {
|
| + unpacker_io_task_runner_(unpacker_io_task_runner) {
|
| // Tracking for crbug.com/692069. The location must be valid. If it's invalid,
|
| // the utility process kills itself for a bad IPC.
|
| CHECK_GT(location, Manifest::INVALID_LOCATION);
|
| @@ -259,8 +256,8 @@ bool SandboxedUnpacker::CreateTempDirectory() {
|
| }
|
|
|
| void SandboxedUnpacker::StartWithCrx(const CRXFileInfo& crx_info) {
|
| - // We assume that we are started on the thread that the client wants us to do
|
| - // file IO on.
|
| + // We assume that we are started on the thread that the client wants us
|
| + // to do file IO on.
|
| CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
|
|
|
| crx_unpack_start_time_ = base::TimeTicks::Now();
|
| @@ -314,12 +311,13 @@ void SandboxedUnpacker::StartWithCrx(const CRXFileInfo& crx_info) {
|
| l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED));
|
| return;
|
| }
|
| +
|
| PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackLinkFreeCrxPathLength",
|
| link_free_crx_path);
|
|
|
| - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&SandboxedUnpacker::StartUnzipOnIOThread,
|
| - this, link_free_crx_path));
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&SandboxedUnpacker::Unzip, this, link_free_crx_path));
|
| }
|
|
|
| void SandboxedUnpacker::StartWithDirectory(const std::string& extension_id,
|
| @@ -342,9 +340,9 @@ void SandboxedUnpacker::StartWithDirectory(const std::string& extension_id,
|
| return;
|
| }
|
|
|
| - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&SandboxedUnpacker::StartUnpackOnIOThread,
|
| - this, extension_root_));
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&SandboxedUnpacker::Unpack, this, extension_root_));
|
| }
|
|
|
| SandboxedUnpacker::~SandboxedUnpacker() {
|
| @@ -353,28 +351,28 @@ SandboxedUnpacker::~SandboxedUnpacker() {
|
| temp_dir_.Take();
|
| }
|
|
|
| -bool SandboxedUnpacker::OnMessageReceived(const IPC::Message& message) {
|
| - bool handled = true;
|
| - IPC_BEGIN_MESSAGE_MAP(SandboxedUnpacker, message)
|
| - IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnzipToDir_Succeeded,
|
| - OnUnzipToDirSucceeded)
|
| - IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnzipToDir_Failed,
|
| - OnUnzipToDirFailed)
|
| - IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnpackExtension_Succeeded,
|
| - OnUnpackExtensionSucceeded)
|
| - IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnpackExtension_Failed,
|
| - OnUnpackExtensionFailed)
|
| - IPC_MESSAGE_UNHANDLED(handled = false)
|
| - IPC_END_MESSAGE_MAP()
|
| - return handled;
|
| -}
|
| +void SandboxedUnpacker::StartUtilityProcessIfNeeded() {
|
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
|
|
| -void SandboxedUnpacker::OnProcessCrashed(int exit_code) {
|
| - // Don't report crashes if they happen after we got a response.
|
| - if (got_response_)
|
| + if (utility_process_mojo_client_)
|
| return;
|
|
|
| - // Utility process crashed while trying to install.
|
| + utility_process_mojo_client_ = base::MakeUnique<
|
| + content::UtilityProcessMojoClient<mojom::ExtensionUnpacker>>(
|
| + l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME));
|
| + utility_process_mojo_client_->set_error_callback(
|
| + base::Bind(&SandboxedUnpacker::UtilityProcessCrashed, this));
|
| +
|
| + utility_process_mojo_client_->set_exposed_directory(temp_dir_.GetPath());
|
| +
|
| + utility_process_mojo_client_->Start();
|
| +}
|
| +
|
| +void SandboxedUnpacker::UtilityProcessCrashed() {
|
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
| +
|
| + utility_process_mojo_client_.reset();
|
| +
|
| ReportFailure(
|
| UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL,
|
| l10n_util::GetStringFUTF16(
|
| @@ -384,60 +382,73 @@ void SandboxedUnpacker::OnProcessCrashed(int exit_code) {
|
| l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_PROCESS_CRASHED));
|
| }
|
|
|
| -void SandboxedUnpacker::StartUnzipOnIOThread(const base::FilePath& crx_path) {
|
| - if (!utility_wrapper_->StartIfNeeded(temp_dir_.GetPath(), this,
|
| - unpacker_io_task_runner_)) {
|
| - ReportFailure(
|
| - COULD_NOT_START_UTILITY_PROCESS,
|
| - l10n_util::GetStringFUTF16(
|
| - IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
|
| - FailureReasonToString16(COULD_NOT_START_UTILITY_PROCESS)));
|
| - return;
|
| - }
|
| +void SandboxedUnpacker::Unzip(const base::FilePath& crx_path) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + StartUtilityProcessIfNeeded();
|
| +
|
| DCHECK(crx_path.DirName() == temp_dir_.GetPath());
|
| base::FilePath unzipped_dir =
|
| crx_path.DirName().AppendASCII(kTempExtensionName);
|
| - utility_wrapper_->host()->Send(
|
| - new ExtensionUtilityMsg_UnzipToDir(crx_path, unzipped_dir));
|
| +
|
| + utility_process_mojo_client_->service()->Unzip(
|
| + crx_path, unzipped_dir,
|
| + base::Bind(&SandboxedUnpacker::UnzipDone, this, unzipped_dir));
|
| }
|
|
|
| -void SandboxedUnpacker::StartUnpackOnIOThread(
|
| - const base::FilePath& directory_path) {
|
| - if (!utility_wrapper_->StartIfNeeded(temp_dir_.GetPath(), this,
|
| - unpacker_io_task_runner_)) {
|
| - ReportFailure(
|
| - COULD_NOT_START_UTILITY_PROCESS,
|
| - l10n_util::GetStringFUTF16(
|
| - IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
|
| - FailureReasonToString16(COULD_NOT_START_UTILITY_PROCESS)));
|
| +void SandboxedUnpacker::UnzipDone(const base::FilePath& directory,
|
| + bool success) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!success) {
|
| + utility_process_mojo_client_.reset();
|
| + ReportFailure(UNZIP_FAILED,
|
| + l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR));
|
| return;
|
| }
|
| - DCHECK(directory_path.DirName() == temp_dir_.GetPath());
|
| - utility_wrapper_->host()->Send(new ExtensionUtilityMsg_UnpackExtension(
|
| - directory_path, extension_id_, location_, creation_flags_));
|
| -}
|
|
|
| -void SandboxedUnpacker::OnUnzipToDirSucceeded(const base::FilePath& directory) {
|
| BrowserThread::PostTask(
|
| BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&SandboxedUnpacker::StartUnpackOnIOThread, this, directory));
|
| + base::Bind(&SandboxedUnpacker::Unpack, this, directory));
|
| +}
|
| +
|
| +void SandboxedUnpacker::Unpack(const base::FilePath& directory) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + StartUtilityProcessIfNeeded();
|
| +
|
| + DCHECK(directory.DirName() == temp_dir_.GetPath());
|
| +
|
| + utility_process_mojo_client_->service()->Unpack(
|
| + directory, extension_id_, location_, creation_flags_,
|
| + base::Bind(&SandboxedUnpacker::UnpackDone, this));
|
| }
|
|
|
| -void SandboxedUnpacker::OnUnzipToDirFailed(const std::string& error) {
|
| - got_response_ = true;
|
| - utility_wrapper_ = nullptr;
|
| - ReportFailure(UNZIP_FAILED,
|
| - l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR));
|
| +void SandboxedUnpacker::UnpackDone(
|
| + const base::string16& error,
|
| + std::unique_ptr<base::DictionaryValue> manifest) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + utility_process_mojo_client_.reset();
|
| +
|
| + if (!error.empty()) {
|
| + unpacker_io_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SandboxedUnpacker::UnpackExtensionFailed, this, error));
|
| + return;
|
| + }
|
| +
|
| + unpacker_io_task_runner_->PostTask(
|
| + FROM_HERE, base::Bind(&SandboxedUnpacker::UnpackExtensionSucceeded, this,
|
| + base::Passed(&manifest)));
|
| }
|
|
|
| -void SandboxedUnpacker::OnUnpackExtensionSucceeded(
|
| - const base::DictionaryValue& manifest) {
|
| +void SandboxedUnpacker::UnpackExtensionSucceeded(
|
| + std::unique_ptr<base::DictionaryValue> manifest) {
|
| CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
|
| - got_response_ = true;
|
| - utility_wrapper_ = nullptr;
|
|
|
| std::unique_ptr<base::DictionaryValue> final_manifest(
|
| - RewriteManifestFile(manifest));
|
| + RewriteManifestFile(*manifest));
|
| if (!final_manifest)
|
| return;
|
|
|
| @@ -477,13 +488,12 @@ void SandboxedUnpacker::OnUnpackExtensionSucceeded(
|
| if (!RewriteCatalogFiles())
|
| return;
|
|
|
| - ReportSuccess(manifest, install_icon);
|
| + ReportSuccess(std::move(manifest), install_icon);
|
| }
|
|
|
| -void SandboxedUnpacker::OnUnpackExtensionFailed(const base::string16& error) {
|
| +void SandboxedUnpacker::UnpackExtensionFailed(const base::string16& error) {
|
| CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
|
| - got_response_ = true;
|
| - utility_wrapper_ = nullptr;
|
| +
|
| ReportFailure(
|
| UNPACKER_CLIENT_FAILED,
|
| l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error));
|
| @@ -572,13 +582,12 @@ base::string16 SandboxedUnpacker::FailureReasonToString16(
|
| return ASCIIToUTF16("UNZIP_FAILED");
|
| case DIRECTORY_MOVE_FAILED:
|
| return ASCIIToUTF16("DIRECTORY_MOVE_FAILED");
|
| - case COULD_NOT_START_UTILITY_PROCESS:
|
| - return ASCIIToUTF16("COULD_NOT_START_UTILITY_PROCESS");
|
|
|
| case NUM_FAILURE_REASONS:
|
| NOTREACHED();
|
| return base::string16();
|
| }
|
| +
|
| NOTREACHED();
|
| return base::string16();
|
| }
|
| @@ -643,12 +652,12 @@ bool SandboxedUnpacker::ValidateSignature(const base::FilePath& crx_path,
|
| FailWithPackageError(CRX_HASH_VERIFICATION_FAILED);
|
| break;
|
| }
|
| +
|
| return false;
|
| }
|
|
|
| void SandboxedUnpacker::ReportFailure(FailureReason reason,
|
| const base::string16& error) {
|
| - utility_wrapper_ = nullptr;
|
| UMA_HISTOGRAM_ENUMERATION("Extensions.SandboxUnpackFailureReason", reason,
|
| NUM_FAILURE_REASONS);
|
| if (!crx_unpack_start_time_.is_null())
|
| @@ -665,9 +674,8 @@ void SandboxedUnpacker::ReportFailure(FailureReason reason,
|
| }
|
|
|
| void SandboxedUnpacker::ReportSuccess(
|
| - const base::DictionaryValue& original_manifest,
|
| + std::unique_ptr<base::DictionaryValue> original_manifest,
|
| const SkBitmap& install_icon) {
|
| - utility_wrapper_ = nullptr;
|
| UMA_HISTOGRAM_COUNTS("Extensions.SandboxUnpackSuccess", 1);
|
|
|
| if (!crx_unpack_start_time_.is_null())
|
| @@ -677,8 +685,11 @@ void SandboxedUnpacker::ReportSuccess(
|
| DCHECK(!temp_dir_.GetPath().empty());
|
|
|
| // Client takes ownership of temporary directory and extension.
|
| + // TODO(https://crbug.com/699528): we should consider transferring the
|
| + // ownership of original_manifest to the client as well.
|
| client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_,
|
| - &original_manifest, extension_.get(), install_icon);
|
| + original_manifest.get(), extension_.get(),
|
| + install_icon);
|
| extension_ = NULL;
|
| }
|
|
|
| @@ -719,6 +730,7 @@ base::DictionaryValue* SandboxedUnpacker::RewriteManifestFile(
|
|
|
| bool SandboxedUnpacker::RewriteImageFiles(SkBitmap* install_icon) {
|
| DCHECK(!temp_dir_.GetPath().empty());
|
| +
|
| DecodedImages images;
|
| if (!ReadImagesFromFile(temp_dir_.GetPath(), &images)) {
|
| // Couldn't read image data from disk.
|
| @@ -794,6 +806,7 @@ bool SandboxedUnpacker::RewriteImageFiles(SkBitmap* install_icon) {
|
| ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE")));
|
| return false;
|
| }
|
| +
|
| base::FilePath path = extension_root_.Append(path_suffix);
|
|
|
| std::vector<unsigned char> image_data;
|
| @@ -860,6 +873,7 @@ bool SandboxedUnpacker::RewriteCatalogFiles() {
|
| ASCIIToUTF16("INVALID_PATH_FOR_CATALOG")));
|
| return false;
|
| }
|
| +
|
| base::FilePath path = extension_root_.Append(relative_path);
|
|
|
| std::string catalog_json;
|
| @@ -898,42 +912,4 @@ void SandboxedUnpacker::Cleanup() {
|
| }
|
| }
|
|
|
| -SandboxedUnpacker::UtilityHostWrapper::UtilityHostWrapper() {}
|
| -
|
| -bool SandboxedUnpacker::UtilityHostWrapper::StartIfNeeded(
|
| - const base::FilePath& exposed_dir,
|
| - const scoped_refptr<UtilityProcessHostClient>& client,
|
| - const scoped_refptr<base::SequencedTaskRunner>& client_task_runner) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (!utility_host_) {
|
| - utility_host_ =
|
| - UtilityProcessHost::Create(client, client_task_runner)->AsWeakPtr();
|
| - utility_host_->SetName(
|
| - l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME));
|
| -
|
| - // Grant the subprocess access to our temp dir so it can write out files.
|
| - DCHECK(!exposed_dir.empty());
|
| - utility_host_->SetExposedDir(exposed_dir);
|
| - if (!utility_host_->StartBatchMode()) {
|
| - utility_host_.reset();
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -content::UtilityProcessHost* SandboxedUnpacker::UtilityHostWrapper::host()
|
| - const {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - return utility_host_.get();
|
| -}
|
| -
|
| -SandboxedUnpacker::UtilityHostWrapper::~UtilityHostWrapper() {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (utility_host_) {
|
| - utility_host_->EndBatchMode();
|
| - utility_host_.reset();
|
| - }
|
| -}
|
| -
|
| } // namespace extensions
|
|
|