• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This file contains the code to apply a Courgette patch.
6 
7 #include "courgette/ensemble.h"
8 
9 #include "base/basictypes.h"
10 #include "base/file_util.h"
11 #include "base/files/memory_mapped_file.h"
12 #include "base/logging.h"
13 #include "courgette/crc.h"
14 #include "courgette/region.h"
15 #include "courgette/streams.h"
16 #include "courgette/simple_delta.h"
17 #include "courgette/patcher_x86_32.h"
18 
19 namespace courgette {
20 
21 // EnsemblePatchApplication is all the logic and data required to apply the
22 // multi-stage patch.
23 class EnsemblePatchApplication {
24  public:
25   EnsemblePatchApplication();
26   ~EnsemblePatchApplication();
27 
28   Status ReadHeader(SourceStream* header_stream);
29 
30   Status InitBase(const Region& region);
31 
32   Status ValidateBase();
33 
34   Status ReadInitialParameters(SourceStream* initial_parameters);
35 
36   Status PredictTransformParameters(SinkStreamSet* predicted_parameters);
37 
38   Status SubpatchTransformParameters(SinkStreamSet* prediction,
39                                      SourceStream* correction,
40                                      SourceStreamSet* corrected_parameters);
41 
42   Status TransformUp(SourceStreamSet* parameters,
43                      SinkStreamSet* transformed_elements);
44 
45   Status SubpatchTransformedElements(SinkStreamSet* elements,
46                                      SourceStream* correction,
47                                      SourceStreamSet* corrected_elements);
48 
49   Status TransformDown(SourceStreamSet* transformed_elements,
50                        SinkStream* basic_elements);
51 
52   Status SubpatchFinalOutput(SourceStream* original,
53                              SourceStream* correction,
54                              SinkStream* corrected_ensemble);
55 
56  private:
57   Status SubpatchStreamSets(SinkStreamSet* predicted_items,
58                             SourceStream* correction,
59                             SourceStreamSet* corrected_items,
60                             SinkStream* corrected_items_storage);
61 
62   Region base_region_;       // Location of in-memory copy of 'old' version.
63 
64   uint32 source_checksum_;
65   uint32 target_checksum_;
66   uint32 final_patch_input_size_prediction_;
67 
68   std::vector<TransformationPatcher*> patchers_;
69 
70   SinkStream corrected_parameters_storage_;
71   SinkStream corrected_elements_storage_;
72 
73   DISALLOW_COPY_AND_ASSIGN(EnsemblePatchApplication);
74 };
75 
EnsemblePatchApplication()76 EnsemblePatchApplication::EnsemblePatchApplication()
77     : source_checksum_(0), target_checksum_(0),
78       final_patch_input_size_prediction_(0) {
79 }
80 
~EnsemblePatchApplication()81 EnsemblePatchApplication::~EnsemblePatchApplication() {
82   for (size_t i = 0;  i < patchers_.size();  ++i) {
83     delete patchers_[i];
84   }
85 }
86 
ReadHeader(SourceStream * header_stream)87 Status EnsemblePatchApplication::ReadHeader(SourceStream* header_stream) {
88   uint32 magic;
89   if (!header_stream->ReadVarint32(&magic))
90     return C_BAD_ENSEMBLE_MAGIC;
91 
92   if (magic != CourgettePatchFile::kMagic)
93     return C_BAD_ENSEMBLE_MAGIC;
94 
95   uint32 version;
96   if (!header_stream->ReadVarint32(&version))
97     return C_BAD_ENSEMBLE_VERSION;
98 
99   if (version != CourgettePatchFile::kVersion)
100     return C_BAD_ENSEMBLE_VERSION;
101 
102   if (!header_stream->ReadVarint32(&source_checksum_))
103     return C_BAD_ENSEMBLE_HEADER;
104 
105   if (!header_stream->ReadVarint32(&target_checksum_))
106     return C_BAD_ENSEMBLE_HEADER;
107 
108   if (!header_stream->ReadVarint32(&final_patch_input_size_prediction_))
109     return C_BAD_ENSEMBLE_HEADER;
110 
111   return C_OK;
112 }
113 
InitBase(const Region & region)114 Status EnsemblePatchApplication::InitBase(const Region& region) {
115   base_region_.assign(region);
116   return C_OK;
117 }
118 
ValidateBase()119 Status EnsemblePatchApplication::ValidateBase() {
120   uint32 checksum = CalculateCrc(base_region_.start(), base_region_.length());
121   if (source_checksum_ != checksum)
122     return C_BAD_ENSEMBLE_CRC;
123 
124   return C_OK;
125 }
126 
ReadInitialParameters(SourceStream * transformation_parameters)127 Status EnsemblePatchApplication::ReadInitialParameters(
128     SourceStream* transformation_parameters) {
129   uint32 number_of_transformations = 0;
130   if (!transformation_parameters->ReadVarint32(&number_of_transformations))
131     return C_BAD_ENSEMBLE_HEADER;
132 
133   for (size_t i = 0;  i < number_of_transformations;  ++i) {
134     uint32 kind;
135     if (!transformation_parameters->ReadVarint32(&kind))
136       return C_BAD_ENSEMBLE_HEADER;
137 
138     TransformationPatcher* patcher = NULL;
139 
140     switch (kind)
141     {
142       case EXE_WIN_32_X86:
143         patcher = new PatcherX86_32(base_region_);
144         break;
145       case EXE_ELF_32_X86:
146         patcher = new PatcherX86_32(base_region_);
147         break;
148       case EXE_ELF_32_ARM:
149         patcher = new PatcherX86_32(base_region_);
150         break;
151       case EXE_WIN_32_X64:
152         patcher = new PatcherX86_32(base_region_);
153         break;
154     }
155 
156     if (patcher)
157       patchers_.push_back(patcher);
158     else
159       return C_BAD_ENSEMBLE_HEADER;
160   }
161 
162   for (size_t i = 0;  i < patchers_.size();  ++i) {
163     Status status = patchers_[i]->Init(transformation_parameters);
164     if (status != C_OK)
165       return status;
166   }
167 
168   // All transformation_parameters should have been consumed by the above loop.
169   if (!transformation_parameters->Empty())
170     return C_BAD_ENSEMBLE_HEADER;
171 
172   return C_OK;
173 }
174 
PredictTransformParameters(SinkStreamSet * all_predicted_parameters)175 Status EnsemblePatchApplication::PredictTransformParameters(
176     SinkStreamSet* all_predicted_parameters) {
177   for (size_t i = 0;  i < patchers_.size();  ++i) {
178     SinkStreamSet single_predicted_parameters;
179     Status status =
180         patchers_[i]->PredictTransformParameters(&single_predicted_parameters);
181     if (status != C_OK)
182       return status;
183     if (!all_predicted_parameters->WriteSet(&single_predicted_parameters))
184       return C_STREAM_ERROR;
185   }
186   return C_OK;
187 }
188 
SubpatchTransformParameters(SinkStreamSet * predicted_parameters,SourceStream * correction,SourceStreamSet * corrected_parameters)189 Status EnsemblePatchApplication::SubpatchTransformParameters(
190     SinkStreamSet* predicted_parameters,
191     SourceStream* correction,
192     SourceStreamSet* corrected_parameters) {
193   return SubpatchStreamSets(predicted_parameters,
194                             correction,
195                             corrected_parameters,
196                             &corrected_parameters_storage_);
197 }
198 
TransformUp(SourceStreamSet * parameters,SinkStreamSet * transformed_elements)199 Status EnsemblePatchApplication::TransformUp(
200     SourceStreamSet* parameters,
201     SinkStreamSet* transformed_elements) {
202   for (size_t i = 0;  i < patchers_.size();  ++i) {
203     SourceStreamSet single_parameters;
204     if (!parameters->ReadSet(&single_parameters))
205       return C_STREAM_ERROR;
206     SinkStreamSet single_transformed_element;
207     Status status = patchers_[i]->Transform(&single_parameters,
208                                             &single_transformed_element);
209     if (status != C_OK)
210       return status;
211     if (!single_parameters.Empty())
212       return C_STREAM_NOT_CONSUMED;
213     if (!transformed_elements->WriteSet(&single_transformed_element))
214       return C_STREAM_ERROR;
215   }
216 
217   if (!parameters->Empty())
218     return C_STREAM_NOT_CONSUMED;
219   return C_OK;
220 }
221 
SubpatchTransformedElements(SinkStreamSet * predicted_elements,SourceStream * correction,SourceStreamSet * corrected_elements)222 Status EnsemblePatchApplication::SubpatchTransformedElements(
223     SinkStreamSet* predicted_elements,
224     SourceStream* correction,
225     SourceStreamSet* corrected_elements) {
226   return SubpatchStreamSets(predicted_elements,
227                             correction,
228                             corrected_elements,
229                             &corrected_elements_storage_);
230 }
231 
TransformDown(SourceStreamSet * transformed_elements,SinkStream * basic_elements)232 Status EnsemblePatchApplication::TransformDown(
233     SourceStreamSet* transformed_elements,
234     SinkStream* basic_elements) {
235   // Construct blob of original input followed by reformed elements.
236 
237   if (!basic_elements->Reserve(final_patch_input_size_prediction_)) {
238     return C_STREAM_ERROR;
239   }
240 
241   // The original input:
242   if (!basic_elements->Write(base_region_.start(), base_region_.length()))
243     return C_STREAM_ERROR;
244 
245   for (size_t i = 0;  i < patchers_.size();  ++i) {
246     SourceStreamSet single_corrected_element;
247     if (!transformed_elements->ReadSet(&single_corrected_element))
248       return C_STREAM_ERROR;
249     Status status = patchers_[i]->Reform(&single_corrected_element,
250                                          basic_elements);
251     if (status != C_OK)
252       return status;
253     if (!single_corrected_element.Empty())
254       return C_STREAM_NOT_CONSUMED;
255   }
256 
257   if (!transformed_elements->Empty())
258     return C_STREAM_NOT_CONSUMED;
259   // We have totally consumed transformed_elements, so can free the
260   // storage to which it referred.
261   corrected_elements_storage_.Retire();
262 
263   return C_OK;
264 }
265 
SubpatchFinalOutput(SourceStream * original,SourceStream * correction,SinkStream * corrected_ensemble)266 Status EnsemblePatchApplication::SubpatchFinalOutput(
267     SourceStream* original,
268     SourceStream* correction,
269     SinkStream* corrected_ensemble) {
270   Status delta_status = ApplySimpleDelta(original, correction,
271                                          corrected_ensemble);
272   if (delta_status != C_OK)
273     return delta_status;
274 
275   if (CalculateCrc(corrected_ensemble->Buffer(),
276                    corrected_ensemble->Length()) != target_checksum_)
277     return C_BAD_ENSEMBLE_CRC;
278 
279   return C_OK;
280 }
281 
SubpatchStreamSets(SinkStreamSet * predicted_items,SourceStream * correction,SourceStreamSet * corrected_items,SinkStream * corrected_items_storage)282 Status EnsemblePatchApplication::SubpatchStreamSets(
283     SinkStreamSet* predicted_items,
284     SourceStream* correction,
285     SourceStreamSet* corrected_items,
286     SinkStream* corrected_items_storage) {
287   SinkStream linearized_predicted_items;
288   if (!predicted_items->CopyTo(&linearized_predicted_items))
289     return C_STREAM_ERROR;
290 
291   SourceStream prediction;
292   prediction.Init(linearized_predicted_items);
293 
294   Status status = ApplySimpleDelta(&prediction,
295                                    correction,
296                                    corrected_items_storage);
297   if (status != C_OK)
298     return status;
299 
300   if (!corrected_items->Init(corrected_items_storage->Buffer(),
301                              corrected_items_storage->Length()))
302     return C_STREAM_ERROR;
303 
304   return C_OK;
305 }
306 
ApplyEnsemblePatch(SourceStream * base,SourceStream * patch,SinkStream * output)307 Status ApplyEnsemblePatch(SourceStream* base,
308                           SourceStream* patch,
309                           SinkStream* output) {
310   Status status;
311   EnsemblePatchApplication patch_process;
312 
313   status = patch_process.ReadHeader(patch);
314   if (status != C_OK)
315     return status;
316 
317   status = patch_process.InitBase(Region(base->Buffer(), base->Remaining()));
318   if (status != C_OK)
319     return status;
320 
321   status = patch_process.ValidateBase();
322   if (status != C_OK)
323     return status;
324 
325   // The rest of the patch stream is a StreamSet.
326   SourceStreamSet patch_streams;
327   patch_streams.Init(patch);
328 
329   SourceStream* transformation_descriptions     = patch_streams.stream(0);
330   SourceStream* parameter_correction            = patch_streams.stream(1);
331   SourceStream* transformed_elements_correction = patch_streams.stream(2);
332   SourceStream* ensemble_correction             = patch_streams.stream(3);
333 
334   status = patch_process.ReadInitialParameters(transformation_descriptions);
335   if (status != C_OK)
336     return status;
337 
338   SinkStreamSet predicted_parameters;
339   status = patch_process.PredictTransformParameters(&predicted_parameters);
340   if (status != C_OK)
341     return status;
342 
343   SourceStreamSet corrected_parameters;
344   status = patch_process.SubpatchTransformParameters(&predicted_parameters,
345                                                      parameter_correction,
346                                                      &corrected_parameters);
347   if (status != C_OK)
348     return status;
349 
350   SinkStreamSet transformed_elements;
351   status = patch_process.TransformUp(&corrected_parameters,
352                                      &transformed_elements);
353   if (status != C_OK)
354     return status;
355 
356   SourceStreamSet corrected_transformed_elements;
357   status = patch_process.SubpatchTransformedElements(
358           &transformed_elements,
359           transformed_elements_correction,
360           &corrected_transformed_elements);
361   if (status != C_OK)
362     return status;
363 
364   SinkStream original_ensemble_and_corrected_base_elements;
365   status = patch_process.TransformDown(
366       &corrected_transformed_elements,
367       &original_ensemble_and_corrected_base_elements);
368   if (status != C_OK)
369     return status;
370 
371   SourceStream final_patch_prediction;
372   final_patch_prediction.Init(original_ensemble_and_corrected_base_elements);
373   status = patch_process.SubpatchFinalOutput(&final_patch_prediction,
374                                              ensemble_correction, output);
375   if (status != C_OK)
376     return status;
377 
378   return C_OK;
379 }
380 
ApplyEnsemblePatch(const base::FilePath::CharType * old_file_name,const base::FilePath::CharType * patch_file_name,const base::FilePath::CharType * new_file_name)381 Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name,
382                           const base::FilePath::CharType* patch_file_name,
383                           const base::FilePath::CharType* new_file_name) {
384   // First read enough of the patch file to validate the header is well-formed.
385   // A few varint32 numbers should fit in 100.
386   base::FilePath patch_file_path(patch_file_name);
387   base::MemoryMappedFile patch_file;
388   if (!patch_file.Initialize(patch_file_path))
389     return C_READ_OPEN_ERROR;
390 
391   // 'Dry-run' the first step of the patch process to validate format of header.
392   SourceStream patch_header_stream;
393   patch_header_stream.Init(patch_file.data(), patch_file.length());
394   EnsemblePatchApplication patch_process;
395   Status status = patch_process.ReadHeader(&patch_header_stream);
396   if (status != C_OK)
397     return status;
398 
399   // Read the old_file.
400   base::FilePath old_file_path(old_file_name);
401   base::MemoryMappedFile old_file;
402   if (!old_file.Initialize(old_file_path))
403     return C_READ_ERROR;
404 
405   // Apply patch on streams.
406   SourceStream old_source_stream;
407   SourceStream patch_source_stream;
408   old_source_stream.Init(old_file.data(), old_file.length());
409   patch_source_stream.Init(patch_file.data(), patch_file.length());
410   SinkStream new_sink_stream;
411   status = ApplyEnsemblePatch(&old_source_stream, &patch_source_stream,
412                               &new_sink_stream);
413   if (status != C_OK)
414     return status;
415 
416   // Write the patched data to |new_file_name|.
417   base::FilePath new_file_path(new_file_name);
418   int written =
419       base::WriteFile(
420           new_file_path,
421           reinterpret_cast<const char*>(new_sink_stream.Buffer()),
422           static_cast<int>(new_sink_stream.Length()));
423   if (written == -1)
424     return C_WRITE_OPEN_ERROR;
425   if (static_cast<size_t>(written) != new_sink_stream.Length())
426     return C_WRITE_ERROR;
427 
428   return C_OK;
429 }
430 
431 }  // namespace
432