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

Side by Side Diff: extensions/browser/sandboxed_unpacker.cc

Issue 2697463002: Convert utility process extension Unpacker IPC to mojo (Closed)
Patch Set: Set the IPC enum traits limit to extensions::Manifest::NUM_LOCATIONS - 1. Created 3 years, 9 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 <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" 21 #include "base/threading/sequenced_worker_pool.h"
25 #include "build/build_config.h" 22 #include "build/build_config.h"
26 #include "components/crx_file/crx_file.h" 23 #include "components/crx_file/crx_file.h"
27 #include "content/public/browser/browser_thread.h" 24 #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" 25 #include "extensions/common/constants.h"
31 #include "extensions/common/extension.h" 26 #include "extensions/common/extension.h"
32 #include "extensions/common/extension_l10n_util.h" 27 #include "extensions/common/extension_l10n_util.h"
33 #include "extensions/common/extension_utility_messages.h" 28 #include "extensions/common/extension_unpacker.mojom.h"
29 #include "extensions/common/extension_utility_types.h"
34 #include "extensions/common/extensions_client.h" 30 #include "extensions/common/extensions_client.h"
35 #include "extensions/common/file_util.h" 31 #include "extensions/common/file_util.h"
36 #include "extensions/common/manifest_constants.h" 32 #include "extensions/common/manifest_constants.h"
37 #include "extensions/common/manifest_handlers/icons_handler.h" 33 #include "extensions/common/manifest_handlers/icons_handler.h"
38 #include "extensions/common/switches.h" 34 #include "extensions/common/switches.h"
39 #include "extensions/strings/grit/extensions_strings.h" 35 #include "extensions/strings/grit/extensions_strings.h"
40 #include "third_party/skia/include/core/SkBitmap.h" 36 #include "third_party/skia/include/core/SkBitmap.h"
41 #include "ui/base/l10n/l10n_util.h" 37 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/gfx/codec/png_codec.h" 38 #include "ui/gfx/codec/png_codec.h"
43 39
44 using base::ASCIIToUTF16; 40 using base::ASCIIToUTF16;
45 using content::BrowserThread; 41 using content::BrowserThread;
46 using content::UtilityProcessHost;
47 using crx_file::CrxFile; 42 using crx_file::CrxFile;
48 43
49 // The following macro makes histograms that record the length of paths 44 // The following macro makes histograms that record the length of paths
50 // in this file much easier to read. 45 // in this file much easier to read.
51 // Windows has a short max path length. If the path length to a 46 // 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 47 // 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 48 // 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 . 49 // path to the temp unpack directory is. See crbug.com/69693 .
55 #define PATH_LENGTH_HISTOGRAM(name, path) \ 50 #define PATH_LENGTH_HISTOGRAM(name, path) \
56 UMA_HISTOGRAM_CUSTOM_COUNTS(name, path.value().length(), 1, 500, 100) 51 UMA_HISTOGRAM_CUSTOM_COUNTS(name, path.value().length(), 1, 500, 100)
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 // and uses NormalizeFilePath to check if the path is junction free. 117 // and uses NormalizeFilePath to check if the path is junction free.
123 bool VerifyJunctionFreeLocation(base::FilePath* temp_dir) { 118 bool VerifyJunctionFreeLocation(base::FilePath* temp_dir) {
124 if (temp_dir->empty()) 119 if (temp_dir->empty())
125 return false; 120 return false;
126 121
127 base::FilePath temp_file; 122 base::FilePath temp_file;
128 if (!base::CreateTemporaryFileInDir(*temp_dir, &temp_file)) { 123 if (!base::CreateTemporaryFileInDir(*temp_dir, &temp_file)) {
129 LOG(ERROR) << temp_dir->value() << " is not writable"; 124 LOG(ERROR) << temp_dir->value() << " is not writable";
130 return false; 125 return false;
131 } 126 }
127
132 // NormalizeFilePath requires a non-empty file, so write some data. 128 // NormalizeFilePath requires a non-empty file, so write some data.
133 // If you change the exit points of this function please make sure all 129 // If you change the exit points of this function please make sure all
134 // exit points delete this temp file! 130 // exit points delete this temp file!
135 if (base::WriteFile(temp_file, ".", 1) != 1) 131 if (base::WriteFile(temp_file, ".", 1) != 1) {
132 base::DeleteFile(temp_file, false);
136 return false; 133 return false;
134 }
137 135
138 base::FilePath normalized_temp_file; 136 base::FilePath normalized_temp_file;
139 bool normalized = base::NormalizeFilePath(temp_file, &normalized_temp_file); 137 bool normalized = base::NormalizeFilePath(temp_file, &normalized_temp_file);
140 if (!normalized) { 138 if (!normalized) {
141 // If |temp_file| contains a link, the sandbox will block al file system 139 // If |temp_file| contains a link, the sandbox will block all file
142 // operations, and the install will fail. 140 // system operations, and the install will fail.
143 LOG(ERROR) << temp_dir->value() << " seem to be on remote drive."; 141 LOG(ERROR) << temp_dir->value() << " seem to be on remote drive.";
144 } else { 142 } else {
145 *temp_dir = normalized_temp_file.DirName(); 143 *temp_dir = normalized_temp_file.DirName();
146 } 144 }
145
147 // Clean up the temp file. 146 // Clean up the temp file.
148 base::DeleteFile(temp_file, false); 147 base::DeleteFile(temp_file, false);
149 148
150 return normalized; 149 return normalized;
151 } 150 }
152 151
153 // This function tries to find a location for unpacking the extension archive 152 // This function tries to find a location for unpacking the extension archive
154 // that is writable and does not lie on a shared drive so that the sandboxed 153 // that is writable and does not lie on a shared drive so that the sandboxed
155 // unpacking process can write there. If no such location exists we can not 154 // unpacking process can write there. If no such location exists we can not
156 // proceed and should fail. 155 // proceed and should fail.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 } 216 }
218 217
219 SandboxedUnpacker::SandboxedUnpacker( 218 SandboxedUnpacker::SandboxedUnpacker(
220 Manifest::Location location, 219 Manifest::Location location,
221 int creation_flags, 220 int creation_flags,
222 const base::FilePath& extensions_dir, 221 const base::FilePath& extensions_dir,
223 const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner, 222 const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner,
224 SandboxedUnpackerClient* client) 223 SandboxedUnpackerClient* client)
225 : client_(client), 224 : client_(client),
226 extensions_dir_(extensions_dir), 225 extensions_dir_(extensions_dir),
227 got_response_(false),
228 location_(location), 226 location_(location),
229 creation_flags_(creation_flags), 227 creation_flags_(creation_flags),
230 unpacker_io_task_runner_(unpacker_io_task_runner), 228 unpacker_io_task_runner_(unpacker_io_task_runner) {
231 utility_wrapper_(new UtilityHostWrapper) {
232 // Tracking for crbug.com/692069. The location must be valid. If it's invalid, 229 // Tracking for crbug.com/692069. The location must be valid. If it's invalid,
233 // the utility process kills itself for a bad IPC. 230 // the utility process kills itself for a bad IPC.
234 CHECK_GT(location, Manifest::INVALID_LOCATION); 231 CHECK_GT(location, Manifest::INVALID_LOCATION);
235 CHECK_LT(location, Manifest::NUM_LOCATIONS); 232 CHECK_LT(location, Manifest::NUM_LOCATIONS);
236 } 233 }
237 234
238 bool SandboxedUnpacker::CreateTempDirectory() { 235 bool SandboxedUnpacker::CreateTempDirectory() {
239 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 236 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
240 237
241 base::FilePath temp_dir; 238 base::FilePath temp_dir;
(...skipping 10 matching lines...) Expand all
252 l10n_util::GetStringFUTF16( 249 l10n_util::GetStringFUTF16(
253 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 250 IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
254 ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY"))); 251 ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY")));
255 return false; 252 return false;
256 } 253 }
257 254
258 return true; 255 return true;
259 } 256 }
260 257
261 void SandboxedUnpacker::StartWithCrx(const CRXFileInfo& crx_info) { 258 void SandboxedUnpacker::StartWithCrx(const CRXFileInfo& crx_info) {
262 // We assume that we are started on the thread that the client wants us to do 259 // We assume that we are started on the thread that the client wants us
263 // file IO on. 260 // to do file IO on.
264 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 261 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
265 262
266 crx_unpack_start_time_ = base::TimeTicks::Now(); 263 crx_unpack_start_time_ = base::TimeTicks::Now();
267 std::string expected_hash; 264 std::string expected_hash;
268 if (!crx_info.expected_hash.empty() && 265 if (!crx_info.expected_hash.empty() &&
269 base::CommandLine::ForCurrentProcess()->HasSwitch( 266 base::CommandLine::ForCurrentProcess()->HasSwitch(
270 extensions::switches::kEnableCrxHashCheck)) { 267 extensions::switches::kEnableCrxHashCheck)) {
271 expected_hash = base::ToLowerASCII(crx_info.expected_hash); 268 expected_hash = base::ToLowerASCII(crx_info.expected_hash);
272 } 269 }
273 270
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 // will cause file system access outside the sandbox path, and the sandbox 304 // will cause file system access outside the sandbox path, and the sandbox
308 // will deny the operation. 305 // will deny the operation.
309 base::FilePath link_free_crx_path; 306 base::FilePath link_free_crx_path;
310 if (!base::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) { 307 if (!base::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) {
311 LOG(ERROR) << "Could not get the normalized path of " 308 LOG(ERROR) << "Could not get the normalized path of "
312 << temp_crx_path.value(); 309 << temp_crx_path.value();
313 ReportFailure(COULD_NOT_GET_SANDBOX_FRIENDLY_PATH, 310 ReportFailure(COULD_NOT_GET_SANDBOX_FRIENDLY_PATH,
314 l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED)); 311 l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED));
315 return; 312 return;
316 } 313 }
314
317 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackLinkFreeCrxPathLength", 315 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackLinkFreeCrxPathLength",
318 link_free_crx_path); 316 link_free_crx_path);
319 317
320 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 318 BrowserThread::PostTask(
321 base::Bind(&SandboxedUnpacker::StartUnzipOnIOThread, 319 BrowserThread::IO, FROM_HERE,
322 this, link_free_crx_path)); 320 base::Bind(&SandboxedUnpacker::Unzip, this, link_free_crx_path));
323 } 321 }
324 322
325 void SandboxedUnpacker::StartWithDirectory(const std::string& extension_id, 323 void SandboxedUnpacker::StartWithDirectory(const std::string& extension_id,
326 const std::string& public_key, 324 const std::string& public_key,
327 const base::FilePath& directory) { 325 const base::FilePath& directory) {
328 extension_id_ = extension_id; 326 extension_id_ = extension_id;
329 public_key_ = public_key; 327 public_key_ = public_key;
330 if (!CreateTempDirectory()) 328 if (!CreateTempDirectory())
331 return; // ReportFailure() already called. 329 return; // ReportFailure() already called.
332 330
333 extension_root_ = temp_dir_.GetPath().AppendASCII(kTempExtensionName); 331 extension_root_ = temp_dir_.GetPath().AppendASCII(kTempExtensionName);
334 332
335 if (!base::Move(directory, extension_root_)) { 333 if (!base::Move(directory, extension_root_)) {
336 LOG(ERROR) << "Could not move " << directory.value() << " to " 334 LOG(ERROR) << "Could not move " << directory.value() << " to "
337 << extension_root_.value(); 335 << extension_root_.value();
338 ReportFailure( 336 ReportFailure(
339 DIRECTORY_MOVE_FAILED, 337 DIRECTORY_MOVE_FAILED,
340 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 338 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
341 ASCIIToUTF16("DIRECTORY_MOVE_FAILED"))); 339 ASCIIToUTF16("DIRECTORY_MOVE_FAILED")));
342 return; 340 return;
343 } 341 }
344 342
345 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 343 BrowserThread::PostTask(
346 base::Bind(&SandboxedUnpacker::StartUnpackOnIOThread, 344 BrowserThread::IO, FROM_HERE,
347 this, extension_root_)); 345 base::Bind(&SandboxedUnpacker::Unpack, this, extension_root_));
348 } 346 }
349 347
350 SandboxedUnpacker::~SandboxedUnpacker() { 348 SandboxedUnpacker::~SandboxedUnpacker() {
351 // To avoid blocking shutdown, don't delete temporary directory here if it 349 // To avoid blocking shutdown, don't delete temporary directory here if it
352 // hasn't been cleaned up or passed on to another owner yet. 350 // hasn't been cleaned up or passed on to another owner yet.
353 temp_dir_.Take(); 351 temp_dir_.Take();
354 } 352 }
355 353
356 bool SandboxedUnpacker::OnMessageReceived(const IPC::Message& message) { 354 void SandboxedUnpacker::StartUtilityProcessIfNeeded() {
357 bool handled = true; 355 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
358 IPC_BEGIN_MESSAGE_MAP(SandboxedUnpacker, message) 356
359 IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnzipToDir_Succeeded, 357 if (utility_process_mojo_client_)
360 OnUnzipToDirSucceeded) 358 return;
361 IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnzipToDir_Failed, 359
362 OnUnzipToDirFailed) 360 utility_process_mojo_client_ = base::MakeUnique<
363 IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnpackExtension_Succeeded, 361 content::UtilityProcessMojoClient<mojom::ExtensionUnpacker>>(
364 OnUnpackExtensionSucceeded) 362 l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME));
365 IPC_MESSAGE_HANDLER(ExtensionUtilityHostMsg_UnpackExtension_Failed, 363 utility_process_mojo_client_->set_error_callback(
366 OnUnpackExtensionFailed) 364 base::Bind(&SandboxedUnpacker::UtilityProcessCrashed, this));
367 IPC_MESSAGE_UNHANDLED(handled = false) 365
368 IPC_END_MESSAGE_MAP() 366 utility_process_mojo_client_->set_exposed_directory(temp_dir_.GetPath());
369 return handled; 367
368 utility_process_mojo_client_->Start();
370 } 369 }
371 370
372 void SandboxedUnpacker::OnProcessCrashed(int exit_code) { 371 void SandboxedUnpacker::UtilityProcessCrashed() {
373 // Don't report crashes if they happen after we got a response. 372 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
374 if (got_response_)
375 return;
376 373
377 // Utility process crashed while trying to install. 374 utility_process_mojo_client_.reset();
375
378 ReportFailure( 376 ReportFailure(
379 UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, 377 UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL,
380 l10n_util::GetStringFUTF16( 378 l10n_util::GetStringFUTF16(
381 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 379 IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
382 ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL")) + 380 ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL")) +
383 ASCIIToUTF16(". ") + 381 ASCIIToUTF16(". ") +
384 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_PROCESS_CRASHED)); 382 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_PROCESS_CRASHED));
385 } 383 }
386 384
387 void SandboxedUnpacker::StartUnzipOnIOThread(const base::FilePath& crx_path) { 385 void SandboxedUnpacker::Unzip(const base::FilePath& crx_path) {
388 if (!utility_wrapper_->StartIfNeeded(temp_dir_.GetPath(), this, 386 DCHECK_CURRENTLY_ON(BrowserThread::IO);
389 unpacker_io_task_runner_)) { 387
390 ReportFailure( 388 StartUtilityProcessIfNeeded();
391 COULD_NOT_START_UTILITY_PROCESS, 389
392 l10n_util::GetStringFUTF16(
393 IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
394 FailureReasonToString16(COULD_NOT_START_UTILITY_PROCESS)));
395 return;
396 }
397 DCHECK(crx_path.DirName() == temp_dir_.GetPath()); 390 DCHECK(crx_path.DirName() == temp_dir_.GetPath());
398 base::FilePath unzipped_dir = 391 base::FilePath unzipped_dir =
399 crx_path.DirName().AppendASCII(kTempExtensionName); 392 crx_path.DirName().AppendASCII(kTempExtensionName);
400 utility_wrapper_->host()->Send( 393
401 new ExtensionUtilityMsg_UnzipToDir(crx_path, unzipped_dir)); 394 utility_process_mojo_client_->service()->Unzip(
395 crx_path, unzipped_dir,
396 base::Bind(&SandboxedUnpacker::UnzipDone, this, unzipped_dir));
402 } 397 }
403 398
404 void SandboxedUnpacker::StartUnpackOnIOThread( 399 void SandboxedUnpacker::UnzipDone(const base::FilePath& directory,
405 const base::FilePath& directory_path) { 400 bool success) {
406 if (!utility_wrapper_->StartIfNeeded(temp_dir_.GetPath(), this, 401 DCHECK_CURRENTLY_ON(BrowserThread::IO);
407 unpacker_io_task_runner_)) { 402
408 ReportFailure( 403 if (!success) {
409 COULD_NOT_START_UTILITY_PROCESS, 404 utility_process_mojo_client_.reset();
410 l10n_util::GetStringFUTF16( 405 ReportFailure(UNZIP_FAILED,
411 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 406 l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR));
412 FailureReasonToString16(COULD_NOT_START_UTILITY_PROCESS)));
413 return; 407 return;
414 } 408 }
415 DCHECK(directory_path.DirName() == temp_dir_.GetPath()); 409
416 utility_wrapper_->host()->Send(new ExtensionUtilityMsg_UnpackExtension( 410 BrowserThread::PostTask(
417 directory_path, extension_id_, location_, creation_flags_)); 411 BrowserThread::IO, FROM_HERE,
412 base::Bind(&SandboxedUnpacker::Unpack, this, directory));
418 } 413 }
419 414
420 void SandboxedUnpacker::OnUnzipToDirSucceeded(const base::FilePath& directory) { 415 void SandboxedUnpacker::Unpack(const base::FilePath& directory) {
421 BrowserThread::PostTask( 416 DCHECK_CURRENTLY_ON(BrowserThread::IO);
422 BrowserThread::IO, FROM_HERE, 417
423 base::Bind(&SandboxedUnpacker::StartUnpackOnIOThread, this, directory)); 418 StartUtilityProcessIfNeeded();
419
420 DCHECK(directory.DirName() == temp_dir_.GetPath());
421
422 utility_process_mojo_client_->service()->Unpack(
423 directory, extension_id_, location_, creation_flags_,
424 base::Bind(&SandboxedUnpacker::UnpackDone, this));
424 } 425 }
425 426
426 void SandboxedUnpacker::OnUnzipToDirFailed(const std::string& error) { 427 void SandboxedUnpacker::UnpackDone(
427 got_response_ = true; 428 const base::string16& error,
428 utility_wrapper_ = nullptr; 429 std::unique_ptr<base::DictionaryValue> manifest) {
429 ReportFailure(UNZIP_FAILED, 430 DCHECK_CURRENTLY_ON(BrowserThread::IO);
430 l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR)); 431
432 utility_process_mojo_client_.reset();
433
434 if (!error.empty()) {
435 unpacker_io_task_runner_->PostTask(
436 FROM_HERE,
437 base::Bind(&SandboxedUnpacker::UnpackExtensionFailed, this, error));
438 return;
439 }
440
441 unpacker_io_task_runner_->PostTask(
442 FROM_HERE, base::Bind(&SandboxedUnpacker::UnpackExtensionSucceeded, this,
443 base::Passed(&manifest)));
431 } 444 }
432 445
433 void SandboxedUnpacker::OnUnpackExtensionSucceeded( 446 void SandboxedUnpacker::UnpackExtensionSucceeded(
434 const base::DictionaryValue& manifest) { 447 std::unique_ptr<base::DictionaryValue> manifest) {
435 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 448 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
436 got_response_ = true;
437 utility_wrapper_ = nullptr;
438 449
439 std::unique_ptr<base::DictionaryValue> final_manifest( 450 std::unique_ptr<base::DictionaryValue> final_manifest(
440 RewriteManifestFile(manifest)); 451 RewriteManifestFile(*manifest));
441 if (!final_manifest) 452 if (!final_manifest)
442 return; 453 return;
443 454
444 // Create an extension object that refers to the temporary location the 455 // Create an extension object that refers to the temporary location the
445 // extension was unpacked to. We use this until the extension is finally 456 // extension was unpacked to. We use this until the extension is finally
446 // installed. For example, the install UI shows images from inside the 457 // installed. For example, the install UI shows images from inside the
447 // extension. 458 // extension.
448 459
449 // Localize manifest now, so confirm UI gets correct extension name. 460 // Localize manifest now, so confirm UI gets correct extension name.
450 461
(...skipping 19 matching lines...) Expand all
470 return; 481 return;
471 } 482 }
472 483
473 SkBitmap install_icon; 484 SkBitmap install_icon;
474 if (!RewriteImageFiles(&install_icon)) 485 if (!RewriteImageFiles(&install_icon))
475 return; 486 return;
476 487
477 if (!RewriteCatalogFiles()) 488 if (!RewriteCatalogFiles())
478 return; 489 return;
479 490
480 ReportSuccess(manifest, install_icon); 491 ReportSuccess(std::move(manifest), install_icon);
481 } 492 }
482 493
483 void SandboxedUnpacker::OnUnpackExtensionFailed(const base::string16& error) { 494 void SandboxedUnpacker::UnpackExtensionFailed(const base::string16& error) {
484 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 495 CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
485 got_response_ = true; 496
486 utility_wrapper_ = nullptr;
487 ReportFailure( 497 ReportFailure(
488 UNPACKER_CLIENT_FAILED, 498 UNPACKER_CLIENT_FAILED,
489 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error)); 499 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error));
490 } 500 }
491 501
492 base::string16 SandboxedUnpacker::FailureReasonToString16( 502 base::string16 SandboxedUnpacker::FailureReasonToString16(
493 FailureReason reason) { 503 FailureReason reason) {
494 switch (reason) { 504 switch (reason) {
495 case COULD_NOT_GET_TEMP_DIRECTORY: 505 case COULD_NOT_GET_TEMP_DIRECTORY:
496 return ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY"); 506 return ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY");
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
565 case ERROR_SAVING_CATALOG: 575 case ERROR_SAVING_CATALOG:
566 return ASCIIToUTF16("ERROR_SAVING_CATALOG"); 576 return ASCIIToUTF16("ERROR_SAVING_CATALOG");
567 577
568 case CRX_HASH_VERIFICATION_FAILED: 578 case CRX_HASH_VERIFICATION_FAILED:
569 return ASCIIToUTF16("CRX_HASH_VERIFICATION_FAILED"); 579 return ASCIIToUTF16("CRX_HASH_VERIFICATION_FAILED");
570 580
571 case UNZIP_FAILED: 581 case UNZIP_FAILED:
572 return ASCIIToUTF16("UNZIP_FAILED"); 582 return ASCIIToUTF16("UNZIP_FAILED");
573 case DIRECTORY_MOVE_FAILED: 583 case DIRECTORY_MOVE_FAILED:
574 return ASCIIToUTF16("DIRECTORY_MOVE_FAILED"); 584 return ASCIIToUTF16("DIRECTORY_MOVE_FAILED");
575 case COULD_NOT_START_UTILITY_PROCESS:
576 return ASCIIToUTF16("COULD_NOT_START_UTILITY_PROCESS");
577 585
578 case NUM_FAILURE_REASONS: 586 case NUM_FAILURE_REASONS:
579 NOTREACHED(); 587 NOTREACHED();
580 return base::string16(); 588 return base::string16();
581 } 589 }
590
582 NOTREACHED(); 591 NOTREACHED();
583 return base::string16(); 592 return base::string16();
584 } 593 }
585 594
586 void SandboxedUnpacker::FailWithPackageError(FailureReason reason) { 595 void SandboxedUnpacker::FailWithPackageError(FailureReason reason) {
587 ReportFailure(reason, 596 ReportFailure(reason,
588 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_CODE, 597 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_CODE,
589 FailureReasonToString16(reason))); 598 FailureReasonToString16(reason)));
590 } 599 }
591 600
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 FailWithPackageError(CRX_SIGNATURE_VERIFICATION_FAILED); 645 FailWithPackageError(CRX_SIGNATURE_VERIFICATION_FAILED);
637 break; 646 break;
638 case CrxFile::ValidateError::CRX_HASH_VERIFICATION_FAILED: 647 case CrxFile::ValidateError::CRX_HASH_VERIFICATION_FAILED:
639 // We should never get this result unless we had specifically asked for 648 // We should never get this result unless we had specifically asked for
640 // verification of the crx file's hash. 649 // verification of the crx file's hash.
641 CHECK(!expected_hash.empty()); 650 CHECK(!expected_hash.empty());
642 UMA_HISTOGRAM_BOOLEAN("Extensions.SandboxUnpackHashCheck", false); 651 UMA_HISTOGRAM_BOOLEAN("Extensions.SandboxUnpackHashCheck", false);
643 FailWithPackageError(CRX_HASH_VERIFICATION_FAILED); 652 FailWithPackageError(CRX_HASH_VERIFICATION_FAILED);
644 break; 653 break;
645 } 654 }
655
646 return false; 656 return false;
647 } 657 }
648 658
649 void SandboxedUnpacker::ReportFailure(FailureReason reason, 659 void SandboxedUnpacker::ReportFailure(FailureReason reason,
650 const base::string16& error) { 660 const base::string16& error) {
651 utility_wrapper_ = nullptr;
652 UMA_HISTOGRAM_ENUMERATION("Extensions.SandboxUnpackFailureReason", reason, 661 UMA_HISTOGRAM_ENUMERATION("Extensions.SandboxUnpackFailureReason", reason,
653 NUM_FAILURE_REASONS); 662 NUM_FAILURE_REASONS);
654 if (!crx_unpack_start_time_.is_null()) 663 if (!crx_unpack_start_time_.is_null())
655 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackFailureTime", 664 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackFailureTime",
656 base::TimeTicks::Now() - crx_unpack_start_time_); 665 base::TimeTicks::Now() - crx_unpack_start_time_);
657 Cleanup(); 666 Cleanup();
658 667
659 CrxInstallError error_info(reason == CRX_HASH_VERIFICATION_FAILED 668 CrxInstallError error_info(reason == CRX_HASH_VERIFICATION_FAILED
660 ? CrxInstallError::ERROR_HASH_MISMATCH 669 ? CrxInstallError::ERROR_HASH_MISMATCH
661 : CrxInstallError::ERROR_OTHER, 670 : CrxInstallError::ERROR_OTHER,
662 error); 671 error);
663 672
664 client_->OnUnpackFailure(error_info); 673 client_->OnUnpackFailure(error_info);
665 } 674 }
666 675
667 void SandboxedUnpacker::ReportSuccess( 676 void SandboxedUnpacker::ReportSuccess(
668 const base::DictionaryValue& original_manifest, 677 std::unique_ptr<base::DictionaryValue> original_manifest,
669 const SkBitmap& install_icon) { 678 const SkBitmap& install_icon) {
670 utility_wrapper_ = nullptr;
671 UMA_HISTOGRAM_COUNTS("Extensions.SandboxUnpackSuccess", 1); 679 UMA_HISTOGRAM_COUNTS("Extensions.SandboxUnpackSuccess", 1);
672 680
673 if (!crx_unpack_start_time_.is_null()) 681 if (!crx_unpack_start_time_.is_null())
674 RecordSuccessfulUnpackTimeHistograms( 682 RecordSuccessfulUnpackTimeHistograms(
675 crx_path_for_histograms_, 683 crx_path_for_histograms_,
676 base::TimeTicks::Now() - crx_unpack_start_time_); 684 base::TimeTicks::Now() - crx_unpack_start_time_);
677 DCHECK(!temp_dir_.GetPath().empty()); 685 DCHECK(!temp_dir_.GetPath().empty());
678 686
679 // Client takes ownership of temporary directory and extension. 687 // Client takes ownership of temporary directory and extension.
688 // TODO(https://crbug.com/699528): we should consider transferring the
689 // ownership of original_manifest to the client as well.
680 client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_, 690 client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_,
681 &original_manifest, extension_.get(), install_icon); 691 original_manifest.get(), extension_.get(),
692 install_icon);
682 extension_ = NULL; 693 extension_ = NULL;
683 } 694 }
684 695
685 base::DictionaryValue* SandboxedUnpacker::RewriteManifestFile( 696 base::DictionaryValue* SandboxedUnpacker::RewriteManifestFile(
686 const base::DictionaryValue& manifest) { 697 const base::DictionaryValue& manifest) {
687 // Add the public key extracted earlier to the parsed manifest and overwrite 698 // Add the public key extracted earlier to the parsed manifest and overwrite
688 // the original manifest. We do this to ensure the manifest doesn't contain an 699 // the original manifest. We do this to ensure the manifest doesn't contain an
689 // exploitable bug that could be used to compromise the browser. 700 // exploitable bug that could be used to compromise the browser.
690 DCHECK(!public_key_.empty()); 701 DCHECK(!public_key_.empty());
691 std::unique_ptr<base::DictionaryValue> final_manifest(manifest.DeepCopy()); 702 std::unique_ptr<base::DictionaryValue> final_manifest(manifest.DeepCopy());
(...skipping 20 matching lines...) Expand all
712 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 723 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
713 ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON"))); 724 ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON")));
714 return NULL; 725 return NULL;
715 } 726 }
716 727
717 return final_manifest.release(); 728 return final_manifest.release();
718 } 729 }
719 730
720 bool SandboxedUnpacker::RewriteImageFiles(SkBitmap* install_icon) { 731 bool SandboxedUnpacker::RewriteImageFiles(SkBitmap* install_icon) {
721 DCHECK(!temp_dir_.GetPath().empty()); 732 DCHECK(!temp_dir_.GetPath().empty());
733
722 DecodedImages images; 734 DecodedImages images;
723 if (!ReadImagesFromFile(temp_dir_.GetPath(), &images)) { 735 if (!ReadImagesFromFile(temp_dir_.GetPath(), &images)) {
724 // Couldn't read image data from disk. 736 // Couldn't read image data from disk.
725 ReportFailure(COULD_NOT_READ_IMAGE_DATA_FROM_DISK, 737 ReportFailure(COULD_NOT_READ_IMAGE_DATA_FROM_DISK,
726 l10n_util::GetStringFUTF16( 738 l10n_util::GetStringFUTF16(
727 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 739 IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
728 ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK"))); 740 ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK")));
729 return false; 741 return false;
730 } 742 }
731 743
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 *install_icon = image; 799 *install_icon = image;
788 800
789 if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { 801 if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) {
790 // Invalid path for bitmap image. 802 // Invalid path for bitmap image.
791 ReportFailure(INVALID_PATH_FOR_BITMAP_IMAGE, 803 ReportFailure(INVALID_PATH_FOR_BITMAP_IMAGE,
792 l10n_util::GetStringFUTF16( 804 l10n_util::GetStringFUTF16(
793 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 805 IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
794 ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE"))); 806 ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE")));
795 return false; 807 return false;
796 } 808 }
809
797 base::FilePath path = extension_root_.Append(path_suffix); 810 base::FilePath path = extension_root_.Append(path_suffix);
798 811
799 std::vector<unsigned char> image_data; 812 std::vector<unsigned char> image_data;
800 // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even 813 // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even
801 // though they may originally be .jpg, etc. Figure something out. 814 // though they may originally be .jpg, etc. Figure something out.
802 // http://code.google.com/p/chromium/issues/detail?id=12459 815 // http://code.google.com/p/chromium/issues/detail?id=12459
803 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { 816 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) {
804 // Error re-encoding theme image. 817 // Error re-encoding theme image.
805 ReportFailure(ERROR_RE_ENCODING_THEME_IMAGE, 818 ReportFailure(ERROR_RE_ENCODING_THEME_IMAGE,
806 l10n_util::GetStringFUTF16( 819 l10n_util::GetStringFUTF16(
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
853 base::FilePath relative_path = base::FilePath::FromUTF8Unsafe(it.key()); 866 base::FilePath relative_path = base::FilePath::FromUTF8Unsafe(it.key());
854 relative_path = relative_path.Append(kMessagesFilename); 867 relative_path = relative_path.Append(kMessagesFilename);
855 if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) { 868 if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) {
856 // Invalid path for catalog. 869 // Invalid path for catalog.
857 ReportFailure( 870 ReportFailure(
858 INVALID_PATH_FOR_CATALOG, 871 INVALID_PATH_FOR_CATALOG,
859 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 872 l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
860 ASCIIToUTF16("INVALID_PATH_FOR_CATALOG"))); 873 ASCIIToUTF16("INVALID_PATH_FOR_CATALOG")));
861 return false; 874 return false;
862 } 875 }
876
863 base::FilePath path = extension_root_.Append(relative_path); 877 base::FilePath path = extension_root_.Append(relative_path);
864 878
865 std::string catalog_json; 879 std::string catalog_json;
866 JSONStringValueSerializer serializer(&catalog_json); 880 JSONStringValueSerializer serializer(&catalog_json);
867 serializer.set_pretty_print(true); 881 serializer.set_pretty_print(true);
868 if (!serializer.Serialize(*catalog)) { 882 if (!serializer.Serialize(*catalog)) {
869 // Error serializing catalog. 883 // Error serializing catalog.
870 ReportFailure(ERROR_SERIALIZING_CATALOG, 884 ReportFailure(ERROR_SERIALIZING_CATALOG,
871 l10n_util::GetStringFUTF16( 885 l10n_util::GetStringFUTF16(
872 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, 886 IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
(...skipping 18 matching lines...) Expand all
891 } 905 }
892 906
893 void SandboxedUnpacker::Cleanup() { 907 void SandboxedUnpacker::Cleanup() {
894 DCHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread()); 908 DCHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
895 if (!temp_dir_.Delete()) { 909 if (!temp_dir_.Delete()) {
896 LOG(WARNING) << "Can not delete temp directory at " 910 LOG(WARNING) << "Can not delete temp directory at "
897 << temp_dir_.GetPath().value(); 911 << temp_dir_.GetPath().value();
898 } 912 }
899 } 913 }
900 914
901 SandboxedUnpacker::UtilityHostWrapper::UtilityHostWrapper() {}
902
903 bool SandboxedUnpacker::UtilityHostWrapper::StartIfNeeded(
904 const base::FilePath& exposed_dir,
905 const scoped_refptr<UtilityProcessHostClient>& client,
906 const scoped_refptr<base::SequencedTaskRunner>& client_task_runner) {
907 DCHECK_CURRENTLY_ON(BrowserThread::IO);
908 if (!utility_host_) {
909 utility_host_ =
910 UtilityProcessHost::Create(client, client_task_runner)->AsWeakPtr();
911 utility_host_->SetName(
912 l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME));
913
914 // Grant the subprocess access to our temp dir so it can write out files.
915 DCHECK(!exposed_dir.empty());
916 utility_host_->SetExposedDir(exposed_dir);
917 if (!utility_host_->StartBatchMode()) {
918 utility_host_.reset();
919 return false;
920 }
921 }
922 return true;
923 }
924
925 content::UtilityProcessHost* SandboxedUnpacker::UtilityHostWrapper::host()
926 const {
927 DCHECK_CURRENTLY_ON(BrowserThread::IO);
928 return utility_host_.get();
929 }
930
931 SandboxedUnpacker::UtilityHostWrapper::~UtilityHostWrapper() {
932 DCHECK_CURRENTLY_ON(BrowserThread::IO);
933 if (utility_host_) {
934 utility_host_->EndBatchMode();
935 utility_host_.reset();
936 }
937 }
938
939 } // namespace extensions 915 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/browser/sandboxed_unpacker.h ('k') | extensions/browser/sandboxed_unpacker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698