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

Side by Side Diff: chrome/browser/component_updater/component_patcher_operation.cc

Issue 25909005: Use UtilityProcessHost to patch files. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@nonblocking
Patch Set: Rebase to 253436 Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/component_updater/component_patcher_operation.h" 5 #include "chrome/browser/component_updater/component_patcher_operation.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h"
10 #include "base/file_util.h" 11 #include "base/file_util.h"
11 #include "base/files/memory_mapped_file.h" 12 #include "base/files/memory_mapped_file.h"
12 #include "base/json/json_file_value_serializer.h" 13 #include "base/json/json_file_value_serializer.h"
13 #include "base/memory/scoped_handle.h" 14 #include "base/memory/scoped_handle.h"
14 #include "base/path_service.h" 15 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
16 #include "chrome/browser/component_updater/component_patcher.h" 17 #include "chrome/browser/component_updater/component_patcher.h"
17 #include "chrome/browser/component_updater/component_updater_service.h" 18 #include "chrome/browser/component_updater/component_updater_service.h"
19 #include "chrome/common/chrome_utility_messages.h"
18 #include "chrome/common/extensions/extension_constants.h" 20 #include "chrome/common/extensions/extension_constants.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/utility_process_host.h"
23 #include "courgette/courgette.h"
24 #include "courgette/third_party/bsdiff.h"
19 #include "crypto/secure_hash.h" 25 #include "crypto/secure_hash.h"
20 #include "crypto/sha2.h" 26 #include "crypto/sha2.h"
21 #include "crypto/signature_verifier.h" 27 #include "crypto/signature_verifier.h"
22 #include "extensions/common/crx_file.h" 28 #include "extensions/common/crx_file.h"
29 #include "ipc/ipc_message_macros.h"
23 #include "third_party/zlib/google/zip.h" 30 #include "third_party/zlib/google/zip.h"
24 31
25 using crypto::SecureHash; 32 using crypto::SecureHash;
26 33
27 namespace component_updater { 34 namespace component_updater {
28 35
29 namespace { 36 namespace {
30 37
31 const char kInput[] = "input"; 38 const char kInput[] = "input";
32 const char kOp[] = "op"; 39 const char kOp[] = "op";
33 const char kOutput[] = "output"; 40 const char kOutput[] = "output";
34 const char kPatch[] = "patch"; 41 const char kPatch[] = "patch";
35 const char kSha256[] = "sha256"; 42 const char kSha256[] = "sha256";
36 43
44 // The integer offset disambiguates between overlapping error ranges.
45 const int kCourgetteErrorOffset = 300;
46 const int kBsdiffErrorOffset = 600;
47
48 class CourgetteTraits : public DeltaUpdateOpPatchTraits {
49 public:
50 virtual int GetErrorOffset() OVERRIDE;
51 virtual int GetSuccessCode() OVERRIDE;
52 virtual IPC::Message* GetPatchMessage(
53 base::FilePath input_abs_path,
54 base::FilePath patch_abs_path,
55 base::FilePath output_abs_path) OVERRIDE;
56 virtual int Patch(base::FilePath input_abs_path,
57 base::FilePath patch_abs_path,
58 base::FilePath output_abs_path) OVERRIDE;
59 };
60
61 int CourgetteTraits::GetErrorOffset() {
62 return kCourgetteErrorOffset;
63 }
64
65 int CourgetteTraits::GetSuccessCode() {
66 return courgette::C_OK;
67 }
68
69 IPC::Message* CourgetteTraits::GetPatchMessage(base::FilePath input_abs_path,
70 base::FilePath patch_abs_path,
71 base::FilePath output_abs_path) {
72 return new ChromeUtilityMsg_PatchFileCourgette(input_abs_path,
73 patch_abs_path,
74 output_abs_path);
75 }
76
77 int CourgetteTraits::Patch(base::FilePath input_abs_path,
78 base::FilePath patch_abs_path,
79 base::FilePath output_abs_path) {
80 return courgette::ApplyEnsemblePatch(input_abs_path.value().c_str(),
81 patch_abs_path.value().c_str(),
82 output_abs_path.value().c_str());
83 }
84
85 class BsdiffTraits : public DeltaUpdateOpPatchTraits {
86 public:
87 virtual int GetErrorOffset() OVERRIDE;
88 virtual int GetSuccessCode() OVERRIDE;
89 virtual IPC::Message* GetPatchMessage(
90 base::FilePath input_abs_path,
91 base::FilePath patch_abs_path,
92 base::FilePath output_abs_path) OVERRIDE;
93 virtual int Patch(base::FilePath input_abs_path,
94 base::FilePath patch_abs_path,
95 base::FilePath output_abs_path) OVERRIDE;
96 };
97
98 int BsdiffTraits::GetErrorOffset() {
99 return kBsdiffErrorOffset;
100 }
101
102 int BsdiffTraits::GetSuccessCode() {
103 return courgette::OK;
104 }
105
106 IPC::Message* BsdiffTraits::GetPatchMessage(base::FilePath input_abs_path,
107 base::FilePath patch_abs_path,
108 base::FilePath output_abs_path) {
109 return new ChromeUtilityMsg_PatchFileBsdiff(input_abs_path,
110 patch_abs_path,
111 output_abs_path);
112 }
113
114 int BsdiffTraits::Patch(base::FilePath input_abs_path,
115 base::FilePath patch_abs_path,
116 base::FilePath output_abs_path) {
117 return courgette::ApplyBinaryPatch(input_abs_path,
118 patch_abs_path,
119 output_abs_path);
120 }
121
37 } // namespace 122 } // namespace
38 123
39 DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command) { 124 DeltaUpdateOpPatchTraits::~DeltaUpdateOpPatchTraits() {
40 std::string operation; 125 }
41 if (!command->GetString(kOp, &operation)) 126
42 return NULL; 127 DeltaUpdateOp* CreateDeltaUpdateOp(const std::string& operation) {
43 if (operation == "copy") 128 if (operation == "copy") {
44 return new DeltaUpdateOpCopy(); 129 return new DeltaUpdateOpCopy();
45 else if (operation == "create") 130 } else if (operation == "create") {
46 return new DeltaUpdateOpCreate(); 131 return new DeltaUpdateOpCreate();
47 else if (operation == "bsdiff") 132 } else if (operation == "bsdiff") {
48 return new DeltaUpdateOpPatchBsdiff(); 133 scoped_ptr<DeltaUpdateOpPatchTraits> traits(new BsdiffTraits());
49 else if (operation == "courgette") 134 return new DeltaUpdateOpPatch(traits.Pass());
50 return new DeltaUpdateOpPatchCourgette(); 135 } else if (operation == "courgette") {
136 scoped_ptr<DeltaUpdateOpPatchTraits> traits(new CourgetteTraits());
137 return new DeltaUpdateOpPatch(traits.Pass());
138 }
51 return NULL; 139 return NULL;
52 } 140 }
53 141
54 DeltaUpdateOp::DeltaUpdateOp() {} 142 DeltaUpdateOp* CreateDeltaUpdateOp(const base::DictionaryValue& command) {
143 std::string operation;
144 if (!command.GetString(kOp, &operation))
145 return NULL;
146 return CreateDeltaUpdateOp(operation);
147 }
148
149 DeltaUpdateOp::DeltaUpdateOp() : in_process_(false) {}
55 150
56 DeltaUpdateOp::~DeltaUpdateOp() {} 151 DeltaUpdateOp::~DeltaUpdateOp() {}
57 152
58 ComponentUnpacker::Error DeltaUpdateOp::Run(base::DictionaryValue* command_args, 153 void DeltaUpdateOp::Run(
59 const base::FilePath& input_dir, 154 base::DictionaryValue* command_args,
60 const base::FilePath& unpack_dir, 155 const base::FilePath& input_dir,
61 ComponentPatcher* patcher, 156 const base::FilePath& unpack_dir,
62 ComponentInstaller* installer, 157 ComponentInstaller* installer,
63 int* error) { 158 bool in_process,
159 const Callback& callback,
160 scoped_refptr<base::SequencedTaskRunner> task_runner) {
161 callback_ = callback;
162 in_process_ = in_process;
163 task_runner_ = task_runner;
64 std::string output_rel_path; 164 std::string output_rel_path;
65 if (!command_args->GetString(kOutput, &output_rel_path) || 165 if (!command_args->GetString(kOutput, &output_rel_path) ||
66 !command_args->GetString(kSha256, &output_sha256_)) 166 !command_args->GetString(kSha256, &output_sha256_)) {
67 return ComponentUnpacker::kDeltaBadCommands; 167 DoneRunning(ComponentUnpacker::kDeltaBadCommands, 0);
168 return;
169 }
68 170
69 output_abs_path_ = unpack_dir.Append( 171 output_abs_path_ = unpack_dir.Append(
70 base::FilePath::FromUTF8Unsafe(output_rel_path)); 172 base::FilePath::FromUTF8Unsafe(output_rel_path));
71 ComponentUnpacker::Error parse_result = DoParseArguments( 173 ComponentUnpacker::Error parse_result = DoParseArguments(
72 command_args, input_dir, installer); 174 command_args, input_dir, installer);
73 if (parse_result != ComponentUnpacker::kNone) 175 if (parse_result != ComponentUnpacker::kNone) {
74 return parse_result; 176 DoneRunning(parse_result, 0);
177 return;
178 }
75 179
76 const base::FilePath parent = output_abs_path_.DirName(); 180 const base::FilePath parent = output_abs_path_.DirName();
77 if (!base::DirectoryExists(parent)) { 181 if (!base::DirectoryExists(parent)) {
78 if (!base::CreateDirectory(parent)) 182 if (!base::CreateDirectory(parent)) {
79 return ComponentUnpacker::kIoError; 183 DoneRunning(ComponentUnpacker::kIoError, 0);
184 return;
185 }
80 } 186 }
81 187
82 ComponentUnpacker::Error run_result = DoRun(patcher, error); 188 DoRun(base::Bind(&DeltaUpdateOp::DoneRunning,
83 if (run_result != ComponentUnpacker::kNone) 189 scoped_refptr<DeltaUpdateOp>(this)));
84 return run_result; 190 }
85 191
86 return CheckHash(); 192 void DeltaUpdateOp::DoneRunning(ComponentUnpacker::Error error,
193 int extended_error) {
194 if (error == ComponentUnpacker::kNone)
195 error = CheckHash();
196 task_runner_->PostTask(FROM_HERE,
197 base::Bind(callback_, error, extended_error));
87 } 198 }
88 199
89 // Uses the hash as a checksum to confirm that the file now residing in the 200 // Uses the hash as a checksum to confirm that the file now residing in the
90 // output directory probably has the contents it should. 201 // output directory probably has the contents it should.
91 ComponentUnpacker::Error DeltaUpdateOp::CheckHash() { 202 ComponentUnpacker::Error DeltaUpdateOp::CheckHash() {
92 std::vector<uint8> expected_hash; 203 std::vector<uint8> expected_hash;
93 if (!base::HexStringToBytes(output_sha256_, &expected_hash) || 204 if (!base::HexStringToBytes(output_sha256_, &expected_hash) ||
94 expected_hash.size() != crypto::kSHA256Length) 205 expected_hash.size() != crypto::kSHA256Length)
95 return ComponentUnpacker::kDeltaVerificationFailure; 206 return ComponentUnpacker::kDeltaVerificationFailure;
96 207
97 base::MemoryMappedFile output_file_mmapped; 208 base::MemoryMappedFile output_file_mmapped;
98 if (!output_file_mmapped.Initialize(output_abs_path_)) 209 if (!output_file_mmapped.Initialize(output_abs_path_))
99 return ComponentUnpacker::kDeltaVerificationFailure; 210 return ComponentUnpacker::kDeltaVerificationFailure;
100 211
101 uint8 actual_hash[crypto::kSHA256Length] = {0}; 212 uint8 actual_hash[crypto::kSHA256Length] = {0};
102 const scoped_ptr<SecureHash> hasher(SecureHash::Create(SecureHash::SHA256)); 213 const scoped_ptr<SecureHash> hasher(SecureHash::Create(SecureHash::SHA256));
103 hasher->Update(output_file_mmapped.data(), output_file_mmapped.length()); 214 hasher->Update(output_file_mmapped.data(), output_file_mmapped.length());
104 hasher->Finish(actual_hash, sizeof(actual_hash)); 215 hasher->Finish(actual_hash, sizeof(actual_hash));
105 if (memcmp(actual_hash, &expected_hash[0], sizeof(actual_hash))) 216 if (memcmp(actual_hash, &expected_hash[0], sizeof(actual_hash)))
106 return ComponentUnpacker::kDeltaVerificationFailure; 217 return ComponentUnpacker::kDeltaVerificationFailure;
107 218
108 return ComponentUnpacker::kNone; 219 return ComponentUnpacker::kNone;
109 } 220 }
110 221
222 bool DeltaUpdateOp::InProcess() {
223 return in_process_;
224 }
225
111 DeltaUpdateOpCopy::DeltaUpdateOpCopy() {} 226 DeltaUpdateOpCopy::DeltaUpdateOpCopy() {}
112 227
228 DeltaUpdateOpCopy::~DeltaUpdateOpCopy() {}
229
113 ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments( 230 ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments(
114 base::DictionaryValue* command_args, 231 base::DictionaryValue* command_args,
115 const base::FilePath& input_dir, 232 const base::FilePath& input_dir,
116 ComponentInstaller* installer) { 233 ComponentInstaller* installer) {
117 std::string input_rel_path; 234 std::string input_rel_path;
118 if (!command_args->GetString(kInput, &input_rel_path)) 235 if (!command_args->GetString(kInput, &input_rel_path))
119 return ComponentUnpacker::kDeltaBadCommands; 236 return ComponentUnpacker::kDeltaBadCommands;
120 237
121 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) 238 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
122 return ComponentUnpacker::kDeltaMissingExistingFile; 239 return ComponentUnpacker::kDeltaMissingExistingFile;
123 240
124 return ComponentUnpacker::kNone; 241 return ComponentUnpacker::kNone;
125 } 242 }
126 243
127 ComponentUnpacker::Error DeltaUpdateOpCopy::DoRun(ComponentPatcher*, 244 void DeltaUpdateOpCopy::DoRun(const Callback& callback) {
128 int* error) {
129 *error = 0;
130 if (!base::CopyFile(input_abs_path_, output_abs_path_)) 245 if (!base::CopyFile(input_abs_path_, output_abs_path_))
131 return ComponentUnpacker::kDeltaOperationFailure; 246 callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0);
132 247 else
133 return ComponentUnpacker::kNone; 248 callback.Run(ComponentUnpacker::kNone, 0);
134 } 249 }
135 250
136 DeltaUpdateOpCreate::DeltaUpdateOpCreate() {} 251 DeltaUpdateOpCreate::DeltaUpdateOpCreate() {}
137 252
253 DeltaUpdateOpCreate::~DeltaUpdateOpCreate() {}
254
138 ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments( 255 ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments(
139 base::DictionaryValue* command_args, 256 base::DictionaryValue* command_args,
140 const base::FilePath& input_dir, 257 const base::FilePath& input_dir,
141 ComponentInstaller* installer) { 258 ComponentInstaller* installer) {
142 std::string patch_rel_path; 259 std::string patch_rel_path;
143 if (!command_args->GetString(kPatch, &patch_rel_path)) 260 if (!command_args->GetString(kPatch, &patch_rel_path))
144 return ComponentUnpacker::kDeltaBadCommands; 261 return ComponentUnpacker::kDeltaBadCommands;
145 262
146 patch_abs_path_ = input_dir.Append( 263 patch_abs_path_ = input_dir.Append(
147 base::FilePath::FromUTF8Unsafe(patch_rel_path)); 264 base::FilePath::FromUTF8Unsafe(patch_rel_path));
148 265
149 return ComponentUnpacker::kNone; 266 return ComponentUnpacker::kNone;
150 } 267 }
151 268
152 ComponentUnpacker::Error DeltaUpdateOpCreate::DoRun(ComponentPatcher*, 269 void DeltaUpdateOpCreate::DoRun(const Callback& callback) {
153 int* error) {
154 *error = 0;
155 if (!base::Move(patch_abs_path_, output_abs_path_)) 270 if (!base::Move(patch_abs_path_, output_abs_path_))
156 return ComponentUnpacker::kDeltaOperationFailure; 271 callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0);
157 272 else
158 return ComponentUnpacker::kNone; 273 callback.Run(ComponentUnpacker::kNone, 0);
159 } 274 }
160 275
161 DeltaUpdateOpPatchBsdiff::DeltaUpdateOpPatchBsdiff() {}
162 276
163 ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoParseArguments( 277 DeltaUpdateOpPatch::DeltaUpdateOpPatch(
278 scoped_ptr<DeltaUpdateOpPatchTraits> traits) {
279 traits_ = traits.Pass();
280 }
281
282 DeltaUpdateOpPatch::~DeltaUpdateOpPatch() {
283 }
284
285 ComponentUnpacker::Error DeltaUpdateOpPatch::DoParseArguments(
164 base::DictionaryValue* command_args, 286 base::DictionaryValue* command_args,
165 const base::FilePath& input_dir, 287 const base::FilePath& input_dir,
166 ComponentInstaller* installer) { 288 ComponentInstaller* installer) {
167 std::string patch_rel_path; 289 std::string patch_rel_path;
168 std::string input_rel_path; 290 std::string input_rel_path;
169 if (!command_args->GetString(kPatch, &patch_rel_path) || 291 if (!command_args->GetString(kPatch, &patch_rel_path) ||
170 !command_args->GetString(kInput, &input_rel_path)) 292 !command_args->GetString(kInput, &input_rel_path))
171 return ComponentUnpacker::kDeltaBadCommands; 293 return ComponentUnpacker::kDeltaBadCommands;
172 294
173 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) 295 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
174 return ComponentUnpacker::kDeltaMissingExistingFile; 296 return ComponentUnpacker::kDeltaMissingExistingFile;
175 297
176 patch_abs_path_ = input_dir.Append( 298 patch_abs_path_ = input_dir.Append(
177 base::FilePath::FromUTF8Unsafe(patch_rel_path)); 299 base::FilePath::FromUTF8Unsafe(patch_rel_path));
178 300
179 return ComponentUnpacker::kNone; 301 return ComponentUnpacker::kNone;
180 } 302 }
181 303
182 ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoRun( 304 void DeltaUpdateOpPatch::DoRun(const Callback& callback) {
183 ComponentPatcher* patcher, 305 callback_ = callback;
184 int* error) { 306 if (!InProcess()) {
185 *error = 0; 307 content::BrowserThread::PostTask(
186 return patcher->Patch(ComponentPatcher::kPatchTypeBsdiff, 308 content::BrowserThread::IO,
187 input_abs_path_, 309 FROM_HERE,
188 patch_abs_path_, 310 base::Bind(&DeltaUpdateOpPatch::StartProcess, base::Unretained(this)));
189 output_abs_path_, 311 return;
190 error); 312 }
313 const int result = traits_->Patch(input_abs_path_,
314 patch_abs_path_,
315 output_abs_path_);
316 if (result == traits_->GetSuccessCode())
317 DonePatching(ComponentUnpacker::kNone, 0);
318 else
319 DonePatching(ComponentUnpacker::kDeltaOperationFailure, result);
191 } 320 }
192 321
193 DeltaUpdateOpPatchCourgette::DeltaUpdateOpPatchCourgette() {} 322 void DeltaUpdateOpPatch::StartProcess() {
194 323 content::UtilityProcessHost* host = content::UtilityProcessHost::Create(
195 ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoParseArguments( 324 this, base::MessageLoopProxy::current().get());
196 base::DictionaryValue* command_args, 325 host->DisableSandbox();
197 const base::FilePath& input_dir, 326 host->Send(traits_->GetPatchMessage(input_abs_path_,
198 ComponentInstaller* installer) { 327 patch_abs_path_,
199 std::string patch_rel_path; 328 output_abs_path_));
200 std::string input_rel_path;
201 if (!command_args->GetString(kPatch, &patch_rel_path) ||
202 !command_args->GetString(kInput, &input_rel_path))
203 return ComponentUnpacker::kDeltaBadCommands;
204
205 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
206 return ComponentUnpacker::kDeltaMissingExistingFile;
207
208 patch_abs_path_ = input_dir.Append(
209 base::FilePath::FromUTF8Unsafe(patch_rel_path));
210
211 return ComponentUnpacker::kNone;
212 } 329 }
213 330
214 ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoRun( 331 void DeltaUpdateOpPatch::DonePatching(ComponentUnpacker::Error error,
215 ComponentPatcher* patcher, 332 int error_code) {
216 int* error) { 333 if (error != ComponentUnpacker::kNone) {
217 *error = 0; 334 error_code += traits_->GetErrorOffset();
218 return patcher->Patch(ComponentPatcher::kPatchTypeCourgette, 335 }
219 input_abs_path_, 336 callback_.Run(error, error_code);
220 patch_abs_path_, 337 }
221 output_abs_path_, 338
222 error); 339 bool DeltaUpdateOpPatch::OnMessageReceived(const IPC::Message& message) {
340 bool handled = true;
341 IPC_BEGIN_MESSAGE_MAP(DeltaUpdateOpPatch, message)
342 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PatchFile_Succeeded,
343 OnPatchSucceeded)
344 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PatchFile_Failed,
345 OnPatchFailed)
346 IPC_MESSAGE_UNHANDLED(handled = false)
347 IPC_END_MESSAGE_MAP()
348 return handled;
349 }
350
351 void DeltaUpdateOpPatch::OnProcessCrashed(int exit_code) {
352 DonePatching(ComponentUnpacker::kDeltaPatchProcessFailure, exit_code);
353 }
354
355 void DeltaUpdateOpPatch::OnPatchSucceeded() {
356 DonePatching(ComponentUnpacker::kNone, 0);
357 }
358
359 void DeltaUpdateOpPatch::OnPatchFailed(int error_code) {
360 DonePatching(ComponentUnpacker::kDeltaOperationFailure, error_code);
223 } 361 }
224 362
225 } // namespace component_updater 363 } // namespace component_updater
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698