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