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 |