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 (!base::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