Home | History | Annotate | Download | only in component_updater
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/component_updater/component_patcher_operation.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/file_util.h"
     11 #include "base/files/memory_mapped_file.h"
     12 #include "base/json/json_file_value_serializer.h"
     13 #include "base/memory/scoped_handle.h"
     14 #include "base/path_service.h"
     15 #include "base/strings/string_number_conversions.h"
     16 #include "chrome/browser/component_updater/component_patcher.h"
     17 #include "chrome/browser/component_updater/component_updater_service.h"
     18 #include "chrome/common/extensions/extension_constants.h"
     19 #include "crypto/secure_hash.h"
     20 #include "crypto/sha2.h"
     21 #include "crypto/signature_verifier.h"
     22 #include "extensions/common/crx_file.h"
     23 #include "third_party/zlib/google/zip.h"
     24 
     25 using crypto::SecureHash;
     26 
     27 namespace {
     28 
     29 const char kInput[] = "input";
     30 const char kOp[] = "op";
     31 const char kOutput[] = "output";
     32 const char kPatch[] = "patch";
     33 const char kSha256[] = "sha256";
     34 
     35 }  // namespace
     36 
     37 DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command) {
     38   std::string operation;
     39   if (!command->GetString(kOp, &operation))
     40     return NULL;
     41   if (operation == "copy")
     42     return new DeltaUpdateOpCopy();
     43   else if (operation == "create")
     44     return new DeltaUpdateOpCreate();
     45   else if (operation == "bsdiff")
     46     return new DeltaUpdateOpPatchBsdiff();
     47   else if (operation == "courgette")
     48     return new DeltaUpdateOpPatchCourgette();
     49   return NULL;
     50 }
     51 
     52 DeltaUpdateOp::DeltaUpdateOp() {}
     53 
     54 DeltaUpdateOp::~DeltaUpdateOp() {}
     55 
     56 ComponentUnpacker::Error DeltaUpdateOp::Run(base::DictionaryValue* command_args,
     57                                             const base::FilePath& input_dir,
     58                                             const base::FilePath& unpack_dir,
     59                                             ComponentPatcher* patcher,
     60                                             ComponentInstaller* installer,
     61                                             int* error) {
     62   std::string output_rel_path;
     63   if (!command_args->GetString(kOutput, &output_rel_path) ||
     64       !command_args->GetString(kSha256, &output_sha256_))
     65     return ComponentUnpacker::kDeltaBadCommands;
     66 
     67   output_abs_path_ = unpack_dir.Append(
     68       base::FilePath::FromUTF8Unsafe(output_rel_path));
     69   ComponentUnpacker::Error parse_result = DoParseArguments(
     70       command_args, input_dir, installer);
     71   if (parse_result != ComponentUnpacker::kNone)
     72     return parse_result;
     73 
     74   const base::FilePath parent = output_abs_path_.DirName();
     75   if (!base::DirectoryExists(parent)) {
     76     if (!file_util::CreateDirectory(parent))
     77       return ComponentUnpacker::kIoError;
     78   }
     79 
     80   ComponentUnpacker::Error run_result = DoRun(patcher, error);
     81   if (run_result != ComponentUnpacker::kNone)
     82     return run_result;
     83 
     84   return CheckHash();
     85 }
     86 
     87 // Uses the hash as a checksum to confirm that the file now residing in the
     88 // output directory probably has the contents it should.
     89 ComponentUnpacker::Error DeltaUpdateOp::CheckHash() {
     90   std::vector<uint8> expected_hash;
     91   if (!base::HexStringToBytes(output_sha256_, &expected_hash) ||
     92       expected_hash.size() != crypto::kSHA256Length)
     93     return ComponentUnpacker::kDeltaVerificationFailure;
     94 
     95   base::MemoryMappedFile output_file_mmapped;
     96   if (!output_file_mmapped.Initialize(output_abs_path_))
     97     return ComponentUnpacker::kDeltaVerificationFailure;
     98 
     99   uint8 actual_hash[crypto::kSHA256Length] = {0};
    100   const scoped_ptr<SecureHash> hasher(SecureHash::Create(SecureHash::SHA256));
    101   hasher->Update(output_file_mmapped.data(), output_file_mmapped.length());
    102   hasher->Finish(actual_hash, sizeof(actual_hash));
    103   if (memcmp(actual_hash, &expected_hash[0], sizeof(actual_hash)))
    104     return ComponentUnpacker::kDeltaVerificationFailure;
    105 
    106   return ComponentUnpacker::kNone;
    107 }
    108 
    109 DeltaUpdateOpCopy::DeltaUpdateOpCopy() {}
    110 
    111 ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments(
    112     base::DictionaryValue* command_args,
    113     const base::FilePath& input_dir,
    114     ComponentInstaller* installer) {
    115   std::string input_rel_path;
    116   if (!command_args->GetString(kInput, &input_rel_path))
    117     return ComponentUnpacker::kDeltaBadCommands;
    118 
    119   if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
    120     return ComponentUnpacker::kDeltaMissingExistingFile;
    121 
    122   return ComponentUnpacker::kNone;
    123 }
    124 
    125 ComponentUnpacker::Error DeltaUpdateOpCopy::DoRun(ComponentPatcher*,
    126                                                   int* error) {
    127   *error = 0;
    128   if (!base::CopyFile(input_abs_path_, output_abs_path_))
    129     return ComponentUnpacker::kDeltaOperationFailure;
    130 
    131   return ComponentUnpacker::kNone;
    132 }
    133 
    134 DeltaUpdateOpCreate::DeltaUpdateOpCreate() {}
    135 
    136 ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments(
    137     base::DictionaryValue* command_args,
    138     const base::FilePath& input_dir,
    139     ComponentInstaller* installer) {
    140   std::string patch_rel_path;
    141   if (!command_args->GetString(kPatch, &patch_rel_path))
    142     return ComponentUnpacker::kDeltaBadCommands;
    143 
    144   patch_abs_path_ = input_dir.Append(
    145       base::FilePath::FromUTF8Unsafe(patch_rel_path));
    146 
    147   return ComponentUnpacker::kNone;
    148 }
    149 
    150 ComponentUnpacker::Error DeltaUpdateOpCreate::DoRun(ComponentPatcher*,
    151                                                     int* error) {
    152   *error = 0;
    153   if (!base::Move(patch_abs_path_, output_abs_path_))
    154     return ComponentUnpacker::kDeltaOperationFailure;
    155 
    156   return ComponentUnpacker::kNone;
    157 }
    158 
    159 DeltaUpdateOpPatchBsdiff::DeltaUpdateOpPatchBsdiff() {}
    160 
    161 ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoParseArguments(
    162     base::DictionaryValue* command_args,
    163     const base::FilePath& input_dir,
    164     ComponentInstaller* installer) {
    165   std::string patch_rel_path;
    166   std::string input_rel_path;
    167   if (!command_args->GetString(kPatch, &patch_rel_path) ||
    168       !command_args->GetString(kInput, &input_rel_path))
    169     return ComponentUnpacker::kDeltaBadCommands;
    170 
    171   if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
    172     return ComponentUnpacker::kDeltaMissingExistingFile;
    173 
    174   patch_abs_path_ = input_dir.Append(
    175       base::FilePath::FromUTF8Unsafe(patch_rel_path));
    176 
    177   return ComponentUnpacker::kNone;
    178 }
    179 
    180 ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoRun(
    181     ComponentPatcher* patcher,
    182     int* error) {
    183   *error = 0;
    184   return patcher->Patch(ComponentPatcher::kPatchTypeBsdiff,
    185                         input_abs_path_,
    186                         patch_abs_path_,
    187                         output_abs_path_,
    188                         error);
    189 }
    190 
    191 DeltaUpdateOpPatchCourgette::DeltaUpdateOpPatchCourgette() {}
    192 
    193 ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoParseArguments(
    194     base::DictionaryValue* command_args,
    195     const base::FilePath& input_dir,
    196     ComponentInstaller* installer) {
    197   std::string patch_rel_path;
    198   std::string input_rel_path;
    199   if (!command_args->GetString(kPatch, &patch_rel_path) ||
    200       !command_args->GetString(kInput, &input_rel_path))
    201     return ComponentUnpacker::kDeltaBadCommands;
    202 
    203   if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
    204     return ComponentUnpacker::kDeltaMissingExistingFile;
    205 
    206   patch_abs_path_ = input_dir.Append(
    207       base::FilePath::FromUTF8Unsafe(patch_rel_path));
    208 
    209   return ComponentUnpacker::kNone;
    210 }
    211 
    212 ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoRun(
    213     ComponentPatcher* patcher,
    214     int* error) {
    215   *error = 0;
    216   return patcher->Patch(ComponentPatcher::kPatchTypeCourgette,
    217                         input_abs_path_,
    218                         patch_abs_path_,
    219                         output_abs_path_,
    220                         error);
    221 }
    222 
    223