Home | History | Annotate | Download | only in courgette
      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 
     76 EnsemblePatchApplication::EnsemblePatchApplication()
     77     : source_checksum_(0), target_checksum_(0),
     78       final_patch_input_size_prediction_(0) {
     79 }
     80 
     81 EnsemblePatchApplication::~EnsemblePatchApplication() {
     82   for (size_t i = 0;  i < patchers_.size();  ++i) {
     83     delete patchers_[i];
     84   }
     85 }
     86 
     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 
    114 Status EnsemblePatchApplication::InitBase(const Region& region) {
    115   base_region_.assign(region);
    116   return C_OK;
    117 }
    118 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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       file_util::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