1 // 2 // Copyright (C) 2012 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "update_engine/payload_consumer/delta_performer.h" 18 19 #include <endian.h> 20 #include <inttypes.h> 21 22 #include <string> 23 #include <vector> 24 25 #include <base/files/file_path.h> 26 #include <base/files/file_util.h> 27 #include <base/files/scoped_temp_dir.h> 28 #include <base/strings/string_number_conversions.h> 29 #include <base/strings/string_util.h> 30 #include <base/strings/stringprintf.h> 31 #include <gmock/gmock.h> 32 #include <google/protobuf/repeated_field.h> 33 #include <gtest/gtest.h> 34 35 #include "update_engine/common/constants.h" 36 #include "update_engine/common/fake_boot_control.h" 37 #include "update_engine/common/fake_hardware.h" 38 #include "update_engine/common/fake_prefs.h" 39 #include "update_engine/common/test_utils.h" 40 #include "update_engine/common/utils.h" 41 #include "update_engine/payload_consumer/mock_download_action.h" 42 #include "update_engine/payload_consumer/payload_constants.h" 43 #include "update_engine/payload_generator/bzip.h" 44 #include "update_engine/payload_generator/extent_ranges.h" 45 #include "update_engine/payload_generator/payload_file.h" 46 #include "update_engine/payload_generator/payload_signer.h" 47 #include "update_engine/update_metadata.pb.h" 48 49 namespace chromeos_update_engine { 50 51 using std::string; 52 using std::vector; 53 using test_utils::GetBuildArtifactsPath; 54 using test_utils::System; 55 using test_utils::kRandomString; 56 using testing::_; 57 58 extern const char* kUnittestPrivateKeyPath; 59 extern const char* kUnittestPublicKeyPath; 60 61 namespace { 62 63 const char kBogusMetadataSignature1[] = 64 "awSFIUdUZz2VWFiR+ku0Pj00V7bPQPQFYQSXjEXr3vaw3TE4xHV5CraY3/YrZpBv" 65 "J5z4dSBskoeuaO1TNC/S6E05t+yt36tE4Fh79tMnJ/z9fogBDXWgXLEUyG78IEQr" 66 "YH6/eBsQGT2RJtBgXIXbZ9W+5G9KmGDoPOoiaeNsDuqHiBc/58OFsrxskH8E6vMS" 67 "BmMGGk82mvgzic7ApcoURbCGey1b3Mwne/hPZ/bb9CIyky8Og9IfFMdL2uAweOIR" 68 "fjoTeLYZpt+WN65Vu7jJ0cQN8e1y+2yka5112wpRf/LLtPgiAjEZnsoYpLUd7CoV" 69 "pLRtClp97kN2+tXGNBQqkA=="; 70 71 // Different options that determine what we should fill into the 72 // install_plan.metadata_signature to simulate the contents received in the 73 // Omaha response. 74 enum MetadataSignatureTest { 75 kEmptyMetadataSignature, 76 kInvalidMetadataSignature, 77 kValidMetadataSignature, 78 }; 79 80 // Compressed data without checksum, generated with: 81 // echo -n a | xz -9 --check=none | hexdump -v -e '" " 12/1 "0x%02x, " "\n"' 82 const uint8_t kXzCompressedData[] = { 83 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x00, 0xff, 0x12, 0xd9, 0x41, 84 0x02, 0x00, 0x21, 0x01, 0x1c, 0x00, 0x00, 0x00, 0x10, 0xcf, 0x58, 0xcc, 85 0x01, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x01, 86 0xad, 0xa6, 0x58, 0x04, 0x06, 0x72, 0x9e, 0x7a, 0x01, 0x00, 0x00, 0x00, 87 0x00, 0x00, 0x59, 0x5a, 88 }; 89 90 // Gzipped 'abc', generated with: 91 // echo -n abc | minigzip | hexdump -v -e '" " 12/1 "0x%02x, " "\n"' 92 const uint8_t kSourceGzippedData[] = { 93 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4b, 0x4c, 94 0x4a, 0x06, 0x00, 0xc2, 0x41, 0x24, 0x35, 0x03, 0x00, 0x00, 0x00, 95 }; 96 97 // Gzipped 'def', generated with: 98 // echo -n def | minigzip | hexdump -v -e '" " 12/1 "0x%02x, " "\n"' 99 const uint8_t kTargetGzippedData[] = { 100 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4b, 0x49, 101 0x4d, 0x03, 0x00, 0x61, 0xe1, 0xc4, 0x0c, 0x03, 0x00, 0x00, 0x00, 102 }; 103 104 // Imgdiff data, generated with: 105 // echo -n abc | minigzip > abc && truncate -s 4096 abc 106 // echo -n def | minigzip > def && truncate -s 4096 def 107 // imgdiff abc def patch && hexdump -v -e '" " 12/1 "0x%02x, " "\n"' patch 108 const uint8_t kImgdiffData[] = { 109 0x49, 0x4d, 0x47, 0x44, 0x49, 0x46, 0x46, 0x32, 0x03, 0x00, 0x00, 0x00, 110 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x1f, 0x8b, 0x08, 0x00, 111 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 113 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 115 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xf1, 0xff, 116 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 117 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x0f, 118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 119 0x00, 0x00, 0x42, 0x53, 0x44, 0x49, 0x46, 0x46, 0x34, 0x30, 0x2a, 0x00, 120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 121 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x5a, 122 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xc3, 0xc8, 0xfb, 0x1f, 123 0x00, 0x00, 0x01, 0x40, 0x00, 0x5c, 0x00, 0x20, 0x00, 0x30, 0xcd, 0x34, 124 0x12, 0x34, 0x54, 0x60, 0x5c, 0xce, 0x2e, 0xe4, 0x8a, 0x70, 0xa1, 0x21, 125 0x87, 0x91, 0xf6, 0x3e, 0x42, 0x5a, 0x68, 0x39, 0x17, 0x72, 0x45, 0x38, 126 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 127 0x59, 0x26, 0x53, 0x59, 0x42, 0x3c, 0xb0, 0xf9, 0x00, 0x00, 0x00, 0x01, 128 0x00, 0x07, 0x00, 0x20, 0x00, 0x21, 0x98, 0x19, 0x84, 0x61, 0x77, 0x24, 129 0x53, 0x85, 0x09, 0x04, 0x23, 0xcb, 0x0f, 0x90, 0x42, 0x53, 0x44, 0x49, 130 0x46, 0x46, 0x34, 0x30, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 131 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x0f, 0x00, 0x00, 132 0x00, 0x00, 0x00, 0x00, 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 133 0x53, 0x59, 0x6f, 0x02, 0x77, 0xf3, 0x00, 0x00, 0x07, 0x40, 0x41, 0xe0, 134 0x10, 0xc0, 0x00, 0x00, 0x02, 0x20, 0x00, 0x20, 0x00, 0x21, 0x29, 0xa3, 135 0x10, 0x86, 0x03, 0x84, 0x04, 0xae, 0x5f, 0x17, 0x72, 0x45, 0x38, 0x50, 136 0x90, 0x6f, 0x02, 0x77, 0xf3, 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 137 0x26, 0x53, 0x59, 0x71, 0x62, 0xbd, 0xa7, 0x00, 0x00, 0x20, 0x40, 0x32, 138 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x80, 0x00, 0x48, 0x20, 0x00, 139 0x30, 0xc0, 0x02, 0xa5, 0x19, 0xa5, 0x92, 0x6f, 0xc2, 0x5d, 0xac, 0x0e, 140 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0x71, 0x62, 0xbd, 0xa7, 0x42, 0x5a, 141 0x68, 0x39, 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, 142 }; 143 144 } // namespace 145 146 class DeltaPerformerTest : public ::testing::Test { 147 protected: 148 void SetUp() override { 149 install_plan_.source_slot = 0; 150 install_plan_.target_slot = 1; 151 EXPECT_CALL(mock_delegate_, ShouldCancel(_)) 152 .WillRepeatedly(testing::Return(false)); 153 } 154 155 // Test helper placed where it can easily be friended from DeltaPerformer. 156 void RunManifestValidation(const DeltaArchiveManifest& manifest, 157 uint64_t major_version, 158 InstallPayloadType payload_type, 159 ErrorCode expected) { 160 install_plan_.payload_type = payload_type; 161 162 // The Manifest we are validating. 163 performer_.manifest_.CopyFrom(manifest); 164 performer_.major_payload_version_ = major_version; 165 166 EXPECT_EQ(expected, performer_.ValidateManifest()); 167 } 168 169 brillo::Blob GeneratePayload(const brillo::Blob& blob_data, 170 const vector<AnnotatedOperation>& aops, 171 bool sign_payload) { 172 return GeneratePayload(blob_data, aops, sign_payload, 173 DeltaPerformer::kSupportedMajorPayloadVersion, 174 DeltaPerformer::kSupportedMinorPayloadVersion); 175 } 176 177 brillo::Blob GeneratePayload(const brillo::Blob& blob_data, 178 const vector<AnnotatedOperation>& aops, 179 bool sign_payload, 180 uint64_t major_version, 181 uint32_t minor_version) { 182 string blob_path; 183 EXPECT_TRUE(utils::MakeTempFile("Blob-XXXXXX", &blob_path, nullptr)); 184 ScopedPathUnlinker blob_unlinker(blob_path); 185 EXPECT_TRUE(utils::WriteFile(blob_path.c_str(), 186 blob_data.data(), 187 blob_data.size())); 188 189 PayloadGenerationConfig config; 190 config.version.major = major_version; 191 config.version.minor = minor_version; 192 193 PayloadFile payload; 194 EXPECT_TRUE(payload.Init(config)); 195 196 PartitionConfig old_part(kLegacyPartitionNameRoot); 197 if (minor_version != kFullPayloadMinorVersion) { 198 // When generating a delta payload we need to include the old partition 199 // information to mark it as a delta payload. 200 old_part.path = "/dev/null"; 201 old_part.size = 0; 202 } 203 PartitionConfig new_part(kLegacyPartitionNameRoot); 204 new_part.path = "/dev/zero"; 205 new_part.size = 1234; 206 207 payload.AddPartition(old_part, new_part, aops); 208 209 // We include a kernel partition without operations. 210 old_part.name = kLegacyPartitionNameKernel; 211 new_part.name = kLegacyPartitionNameKernel; 212 new_part.size = 0; 213 payload.AddPartition(old_part, new_part, {}); 214 215 string payload_path; 216 EXPECT_TRUE(utils::MakeTempFile("Payload-XXXXXX", &payload_path, nullptr)); 217 ScopedPathUnlinker payload_unlinker(payload_path); 218 string private_key = 219 sign_payload ? GetBuildArtifactsPath(kUnittestPrivateKeyPath) : ""; 220 EXPECT_TRUE(payload.WritePayload( 221 payload_path, blob_path, private_key, &install_plan_.metadata_size)); 222 223 brillo::Blob payload_data; 224 EXPECT_TRUE(utils::ReadFile(payload_path, &payload_data)); 225 return payload_data; 226 } 227 228 // Apply |payload_data| on partition specified in |source_path|. 229 // Expect result of performer_.Write() to be |expect_success|. 230 // Returns the result of the payload application. 231 brillo::Blob ApplyPayload(const brillo::Blob& payload_data, 232 const string& source_path, 233 bool expect_success) { 234 return ApplyPayloadToData(payload_data, source_path, brillo::Blob(), 235 expect_success); 236 } 237 238 // Apply the payload provided in |payload_data| reading from the |source_path| 239 // file and writing the contents to a new partition. The existing data in the 240 // new target file are set to |target_data| before applying the payload. 241 // Expect result of performer_.Write() to be |expect_success|. 242 // Returns the result of the payload application. 243 brillo::Blob ApplyPayloadToData(const brillo::Blob& payload_data, 244 const string& source_path, 245 const brillo::Blob& target_data, 246 bool expect_success) { 247 string new_part; 248 EXPECT_TRUE(utils::MakeTempFile("Partition-XXXXXX", &new_part, nullptr)); 249 ScopedPathUnlinker partition_unlinker(new_part); 250 EXPECT_TRUE(utils::WriteFile(new_part.c_str(), target_data.data(), 251 target_data.size())); 252 253 // We installed the operations only in the rootfs partition, but the 254 // delta performer needs to access all the partitions. 255 fake_boot_control_.SetPartitionDevice( 256 kLegacyPartitionNameRoot, install_plan_.target_slot, new_part); 257 fake_boot_control_.SetPartitionDevice( 258 kLegacyPartitionNameRoot, install_plan_.source_slot, source_path); 259 fake_boot_control_.SetPartitionDevice( 260 kLegacyPartitionNameKernel, install_plan_.target_slot, "/dev/null"); 261 fake_boot_control_.SetPartitionDevice( 262 kLegacyPartitionNameKernel, install_plan_.source_slot, "/dev/null"); 263 264 EXPECT_EQ(expect_success, 265 performer_.Write(payload_data.data(), payload_data.size())); 266 EXPECT_EQ(0, performer_.Close()); 267 268 brillo::Blob partition_data; 269 EXPECT_TRUE(utils::ReadFile(new_part, &partition_data)); 270 return partition_data; 271 } 272 273 // Calls delta performer's Write method by pretending to pass in bytes from a 274 // delta file whose metadata size is actual_metadata_size and tests if all 275 // checks are correctly performed if the install plan contains 276 // expected_metadata_size and that the result of the parsing are as per 277 // hash_checks_mandatory flag. 278 void DoMetadataSizeTest(uint64_t expected_metadata_size, 279 uint64_t actual_metadata_size, 280 bool hash_checks_mandatory) { 281 install_plan_.hash_checks_mandatory = hash_checks_mandatory; 282 283 // Set a valid magic string and version number 1. 284 EXPECT_TRUE(performer_.Write("CrAU", 4)); 285 uint64_t version = htobe64(kChromeOSMajorPayloadVersion); 286 EXPECT_TRUE(performer_.Write(&version, 8)); 287 288 install_plan_.metadata_size = expected_metadata_size; 289 ErrorCode error_code; 290 // When filling in size in manifest, exclude the size of the 20-byte header. 291 uint64_t size_in_manifest = htobe64(actual_metadata_size - 20); 292 bool result = performer_.Write(&size_in_manifest, 8, &error_code); 293 if (expected_metadata_size == actual_metadata_size || 294 !hash_checks_mandatory) { 295 EXPECT_TRUE(result); 296 } else { 297 EXPECT_FALSE(result); 298 EXPECT_EQ(ErrorCode::kDownloadInvalidMetadataSize, error_code); 299 } 300 301 EXPECT_LT(performer_.Close(), 0); 302 } 303 304 // Generates a valid delta file but tests the delta performer by suppling 305 // different metadata signatures as per metadata_signature_test flag and 306 // sees if the result of the parsing are as per hash_checks_mandatory flag. 307 void DoMetadataSignatureTest(MetadataSignatureTest metadata_signature_test, 308 bool sign_payload, 309 bool hash_checks_mandatory) { 310 // Loads the payload and parses the manifest. 311 brillo::Blob payload = GeneratePayload(brillo::Blob(), 312 vector<AnnotatedOperation>(), sign_payload, 313 kChromeOSMajorPayloadVersion, kFullPayloadMinorVersion); 314 315 LOG(INFO) << "Payload size: " << payload.size(); 316 317 install_plan_.hash_checks_mandatory = hash_checks_mandatory; 318 319 DeltaPerformer::MetadataParseResult expected_result, actual_result; 320 ErrorCode expected_error, actual_error; 321 322 // Fill up the metadata signature in install plan according to the test. 323 switch (metadata_signature_test) { 324 case kEmptyMetadataSignature: 325 install_plan_.metadata_signature.clear(); 326 expected_result = DeltaPerformer::kMetadataParseError; 327 expected_error = ErrorCode::kDownloadMetadataSignatureMissingError; 328 break; 329 330 case kInvalidMetadataSignature: 331 install_plan_.metadata_signature = kBogusMetadataSignature1; 332 expected_result = DeltaPerformer::kMetadataParseError; 333 expected_error = ErrorCode::kDownloadMetadataSignatureMismatch; 334 break; 335 336 case kValidMetadataSignature: 337 default: 338 // Set the install plan's metadata size to be the same as the one 339 // in the manifest so that we pass the metadata size checks. Only 340 // then we can get to manifest signature checks. 341 ASSERT_TRUE(PayloadSigner::GetMetadataSignature( 342 payload.data(), 343 install_plan_.metadata_size, 344 GetBuildArtifactsPath(kUnittestPrivateKeyPath), 345 &install_plan_.metadata_signature)); 346 EXPECT_FALSE(install_plan_.metadata_signature.empty()); 347 expected_result = DeltaPerformer::kMetadataParseSuccess; 348 expected_error = ErrorCode::kSuccess; 349 break; 350 } 351 352 // Ignore the expected result/error if hash checks are not mandatory. 353 if (!hash_checks_mandatory) { 354 expected_result = DeltaPerformer::kMetadataParseSuccess; 355 expected_error = ErrorCode::kSuccess; 356 } 357 358 // Use the public key corresponding to the private key used above to 359 // sign the metadata. 360 string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath); 361 EXPECT_TRUE(utils::FileExists(public_key_path.c_str())); 362 performer_.set_public_key_path(public_key_path); 363 364 // Init actual_error with an invalid value so that we make sure 365 // ParsePayloadMetadata properly populates it in all cases. 366 actual_error = ErrorCode::kUmaReportedMax; 367 actual_result = performer_.ParsePayloadMetadata(payload, &actual_error); 368 369 EXPECT_EQ(expected_result, actual_result); 370 EXPECT_EQ(expected_error, actual_error); 371 372 // Check that the parsed metadata size is what's expected. This test 373 // implicitly confirms that the metadata signature is valid, if required. 374 EXPECT_EQ(install_plan_.metadata_size, performer_.GetMetadataSize()); 375 } 376 377 void SetSupportedMajorVersion(uint64_t major_version) { 378 performer_.supported_major_version_ = major_version; 379 } 380 FakePrefs prefs_; 381 InstallPlan install_plan_; 382 FakeBootControl fake_boot_control_; 383 FakeHardware fake_hardware_; 384 MockDownloadActionDelegate mock_delegate_; 385 DeltaPerformer performer_{ 386 &prefs_, &fake_boot_control_, &fake_hardware_, &mock_delegate_, &install_plan_}; 387 }; 388 389 TEST_F(DeltaPerformerTest, FullPayloadWriteTest) { 390 install_plan_.payload_type = InstallPayloadType::kFull; 391 brillo::Blob expected_data = brillo::Blob(std::begin(kRandomString), 392 std::end(kRandomString)); 393 expected_data.resize(4096); // block size 394 vector<AnnotatedOperation> aops; 395 AnnotatedOperation aop; 396 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1); 397 aop.op.set_data_offset(0); 398 aop.op.set_data_length(expected_data.size()); 399 aop.op.set_type(InstallOperation::REPLACE); 400 aops.push_back(aop); 401 402 brillo::Blob payload_data = GeneratePayload(expected_data, aops, false, 403 kChromeOSMajorPayloadVersion, kFullPayloadMinorVersion); 404 405 EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true)); 406 } 407 408 TEST_F(DeltaPerformerTest, ShouldCancelTest) { 409 install_plan_.payload_type = InstallPayloadType::kFull; 410 brillo::Blob expected_data = brillo::Blob(std::begin(kRandomString), 411 std::end(kRandomString)); 412 expected_data.resize(4096); // block size 413 vector<AnnotatedOperation> aops; 414 AnnotatedOperation aop; 415 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1); 416 aop.op.set_data_offset(0); 417 aop.op.set_data_length(expected_data.size()); 418 aop.op.set_type(InstallOperation::REPLACE); 419 aops.push_back(aop); 420 421 brillo::Blob payload_data = GeneratePayload(expected_data, aops, false, 422 kChromeOSMajorPayloadVersion, kFullPayloadMinorVersion); 423 424 testing::Mock::VerifyAndClearExpectations(&mock_delegate_); 425 EXPECT_CALL(mock_delegate_, ShouldCancel(_)) 426 .WillOnce( 427 testing::DoAll(testing::SetArgumentPointee<0>(ErrorCode::kError), 428 testing::Return(true))); 429 430 ApplyPayload(payload_data, "/dev/null", false); 431 } 432 433 TEST_F(DeltaPerformerTest, ReplaceOperationTest) { 434 brillo::Blob expected_data = brillo::Blob(std::begin(kRandomString), 435 std::end(kRandomString)); 436 expected_data.resize(4096); // block size 437 vector<AnnotatedOperation> aops; 438 AnnotatedOperation aop; 439 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1); 440 aop.op.set_data_offset(0); 441 aop.op.set_data_length(expected_data.size()); 442 aop.op.set_type(InstallOperation::REPLACE); 443 aops.push_back(aop); 444 445 brillo::Blob payload_data = GeneratePayload(expected_data, aops, false); 446 447 EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true)); 448 } 449 450 TEST_F(DeltaPerformerTest, ReplaceBzOperationTest) { 451 brillo::Blob expected_data = brillo::Blob(std::begin(kRandomString), 452 std::end(kRandomString)); 453 expected_data.resize(4096); // block size 454 brillo::Blob bz_data; 455 EXPECT_TRUE(BzipCompress(expected_data, &bz_data)); 456 457 vector<AnnotatedOperation> aops; 458 AnnotatedOperation aop; 459 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1); 460 aop.op.set_data_offset(0); 461 aop.op.set_data_length(bz_data.size()); 462 aop.op.set_type(InstallOperation::REPLACE_BZ); 463 aops.push_back(aop); 464 465 brillo::Blob payload_data = GeneratePayload(bz_data, aops, false); 466 467 EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true)); 468 } 469 470 TEST_F(DeltaPerformerTest, ReplaceXzOperationTest) { 471 brillo::Blob xz_data(std::begin(kXzCompressedData), 472 std::end(kXzCompressedData)); 473 // The compressed xz data contains only a single "a", but the operation should 474 // pad the rest of the two blocks with zeros. 475 brillo::Blob expected_data = brillo::Blob(4096, 0); 476 expected_data[0] = 'a'; 477 478 AnnotatedOperation aop; 479 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1); 480 aop.op.set_data_offset(0); 481 aop.op.set_data_length(xz_data.size()); 482 aop.op.set_type(InstallOperation::REPLACE_XZ); 483 vector<AnnotatedOperation> aops = {aop}; 484 485 brillo::Blob payload_data = GeneratePayload(xz_data, aops, false); 486 487 EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true)); 488 } 489 490 TEST_F(DeltaPerformerTest, ZeroOperationTest) { 491 brillo::Blob existing_data = brillo::Blob(4096 * 10, 'a'); 492 brillo::Blob expected_data = existing_data; 493 // Blocks 4, 5 and 7 should have zeros instead of 'a' after the operation is 494 // applied. 495 std::fill(expected_data.data() + 4096 * 4, expected_data.data() + 4096 * 6, 496 0); 497 std::fill(expected_data.data() + 4096 * 7, expected_data.data() + 4096 * 8, 498 0); 499 500 AnnotatedOperation aop; 501 *(aop.op.add_dst_extents()) = ExtentForRange(4, 2); 502 *(aop.op.add_dst_extents()) = ExtentForRange(7, 1); 503 aop.op.set_type(InstallOperation::ZERO); 504 vector<AnnotatedOperation> aops = {aop}; 505 506 brillo::Blob payload_data = GeneratePayload(brillo::Blob(), aops, false); 507 508 EXPECT_EQ(expected_data, 509 ApplyPayloadToData(payload_data, "/dev/null", existing_data, true)); 510 } 511 512 TEST_F(DeltaPerformerTest, SourceCopyOperationTest) { 513 brillo::Blob expected_data(std::begin(kRandomString), 514 std::end(kRandomString)); 515 expected_data.resize(4096); // block size 516 AnnotatedOperation aop; 517 *(aop.op.add_src_extents()) = ExtentForRange(0, 1); 518 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1); 519 aop.op.set_type(InstallOperation::SOURCE_COPY); 520 brillo::Blob src_hash; 521 EXPECT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash)); 522 aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size()); 523 524 brillo::Blob payload_data = GeneratePayload(brillo::Blob(), {aop}, false); 525 526 string source_path; 527 EXPECT_TRUE(utils::MakeTempFile("Source-XXXXXX", 528 &source_path, nullptr)); 529 ScopedPathUnlinker path_unlinker(source_path); 530 EXPECT_TRUE(utils::WriteFile(source_path.c_str(), 531 expected_data.data(), 532 expected_data.size())); 533 534 EXPECT_EQ(expected_data, ApplyPayload(payload_data, source_path, true)); 535 } 536 537 TEST_F(DeltaPerformerTest, ImgdiffOperationTest) { 538 brillo::Blob imgdiff_data(std::begin(kImgdiffData), std::end(kImgdiffData)); 539 540 AnnotatedOperation aop; 541 *(aop.op.add_src_extents()) = ExtentForRange(0, 1); 542 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1); 543 aop.op.set_data_offset(0); 544 aop.op.set_data_length(imgdiff_data.size()); 545 aop.op.set_type(InstallOperation::IMGDIFF); 546 547 brillo::Blob payload_data = GeneratePayload(imgdiff_data, {aop}, false); 548 549 string source_path; 550 EXPECT_TRUE(utils::MakeTempFile("Source-XXXXXX", &source_path, nullptr)); 551 ScopedPathUnlinker path_unlinker(source_path); 552 brillo::Blob source_data(std::begin(kSourceGzippedData), 553 std::end(kSourceGzippedData)); 554 source_data.resize(4096); // block size 555 EXPECT_TRUE(utils::WriteFile( 556 source_path.c_str(), source_data.data(), source_data.size())); 557 558 brillo::Blob target_data(std::begin(kTargetGzippedData), 559 std::end(kTargetGzippedData)); 560 target_data.resize(4096); // block size 561 EXPECT_EQ(target_data, ApplyPayload(payload_data, source_path, true)); 562 } 563 564 TEST_F(DeltaPerformerTest, SourceHashMismatchTest) { 565 brillo::Blob expected_data = {'f', 'o', 'o'}; 566 brillo::Blob actual_data = {'b', 'a', 'r'}; 567 expected_data.resize(4096); // block size 568 actual_data.resize(4096); // block size 569 570 AnnotatedOperation aop; 571 *(aop.op.add_src_extents()) = ExtentForRange(0, 1); 572 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1); 573 aop.op.set_type(InstallOperation::SOURCE_COPY); 574 brillo::Blob src_hash; 575 EXPECT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash)); 576 aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size()); 577 578 brillo::Blob payload_data = GeneratePayload(brillo::Blob(), {aop}, false); 579 580 string source_path; 581 EXPECT_TRUE(utils::MakeTempFile("Source-XXXXXX", &source_path, nullptr)); 582 ScopedPathUnlinker path_unlinker(source_path); 583 EXPECT_TRUE(utils::WriteFile(source_path.c_str(), actual_data.data(), 584 actual_data.size())); 585 586 EXPECT_EQ(actual_data, ApplyPayload(payload_data, source_path, false)); 587 } 588 589 TEST_F(DeltaPerformerTest, ExtentsToByteStringTest) { 590 uint64_t test[] = {1, 1, 4, 2, 0, 1}; 591 static_assert(arraysize(test) % 2 == 0, "Array size uneven"); 592 const uint64_t block_size = 4096; 593 const uint64_t file_length = 4 * block_size - 13; 594 595 google::protobuf::RepeatedPtrField<Extent> extents; 596 for (size_t i = 0; i < arraysize(test); i += 2) { 597 *(extents.Add()) = ExtentForRange(test[i], test[i + 1]); 598 } 599 600 string expected_output = "4096:4096,16384:8192,0:4083"; 601 string actual_output; 602 EXPECT_TRUE(DeltaPerformer::ExtentsToBsdiffPositionsString(extents, 603 block_size, 604 file_length, 605 &actual_output)); 606 EXPECT_EQ(expected_output, actual_output); 607 } 608 609 TEST_F(DeltaPerformerTest, ValidateManifestFullGoodTest) { 610 // The Manifest we are validating. 611 DeltaArchiveManifest manifest; 612 manifest.mutable_new_kernel_info(); 613 manifest.mutable_new_rootfs_info(); 614 manifest.set_minor_version(kFullPayloadMinorVersion); 615 616 RunManifestValidation(manifest, 617 kChromeOSMajorPayloadVersion, 618 InstallPayloadType::kFull, 619 ErrorCode::kSuccess); 620 } 621 622 TEST_F(DeltaPerformerTest, ValidateManifestDeltaGoodTest) { 623 // The Manifest we are validating. 624 DeltaArchiveManifest manifest; 625 manifest.mutable_old_kernel_info(); 626 manifest.mutable_old_rootfs_info(); 627 manifest.mutable_new_kernel_info(); 628 manifest.mutable_new_rootfs_info(); 629 manifest.set_minor_version(DeltaPerformer::kSupportedMinorPayloadVersion); 630 631 RunManifestValidation(manifest, 632 kChromeOSMajorPayloadVersion, 633 InstallPayloadType::kDelta, 634 ErrorCode::kSuccess); 635 } 636 637 TEST_F(DeltaPerformerTest, ValidateManifestFullUnsetMinorVersion) { 638 // The Manifest we are validating. 639 DeltaArchiveManifest manifest; 640 641 RunManifestValidation(manifest, 642 DeltaPerformer::kSupportedMajorPayloadVersion, 643 InstallPayloadType::kFull, 644 ErrorCode::kSuccess); 645 } 646 647 TEST_F(DeltaPerformerTest, ValidateManifestDeltaUnsetMinorVersion) { 648 // The Manifest we are validating. 649 DeltaArchiveManifest manifest; 650 // Add an empty old_rootfs_info() to trick the DeltaPerformer into think that 651 // this is a delta payload manifest with a missing minor version. 652 manifest.mutable_old_rootfs_info(); 653 654 RunManifestValidation(manifest, 655 DeltaPerformer::kSupportedMajorPayloadVersion, 656 InstallPayloadType::kDelta, 657 ErrorCode::kUnsupportedMinorPayloadVersion); 658 } 659 660 TEST_F(DeltaPerformerTest, ValidateManifestFullOldKernelTest) { 661 // The Manifest we are validating. 662 DeltaArchiveManifest manifest; 663 manifest.mutable_old_kernel_info(); 664 manifest.mutable_new_kernel_info(); 665 manifest.mutable_new_rootfs_info(); 666 manifest.set_minor_version(DeltaPerformer::kSupportedMinorPayloadVersion); 667 668 RunManifestValidation(manifest, 669 kChromeOSMajorPayloadVersion, 670 InstallPayloadType::kFull, 671 ErrorCode::kPayloadMismatchedType); 672 } 673 674 TEST_F(DeltaPerformerTest, ValidateManifestFullOldRootfsTest) { 675 // The Manifest we are validating. 676 DeltaArchiveManifest manifest; 677 manifest.mutable_old_rootfs_info(); 678 manifest.mutable_new_kernel_info(); 679 manifest.mutable_new_rootfs_info(); 680 manifest.set_minor_version(DeltaPerformer::kSupportedMinorPayloadVersion); 681 682 RunManifestValidation(manifest, 683 kChromeOSMajorPayloadVersion, 684 InstallPayloadType::kFull, 685 ErrorCode::kPayloadMismatchedType); 686 } 687 688 TEST_F(DeltaPerformerTest, ValidateManifestFullPartitionUpdateTest) { 689 // The Manifest we are validating. 690 DeltaArchiveManifest manifest; 691 PartitionUpdate* partition = manifest.add_partitions(); 692 partition->mutable_old_partition_info(); 693 partition->mutable_new_partition_info(); 694 manifest.set_minor_version(DeltaPerformer::kSupportedMinorPayloadVersion); 695 696 RunManifestValidation(manifest, 697 kBrilloMajorPayloadVersion, 698 InstallPayloadType::kFull, 699 ErrorCode::kPayloadMismatchedType); 700 } 701 702 TEST_F(DeltaPerformerTest, ValidateManifestBadMinorVersion) { 703 // The Manifest we are validating. 704 DeltaArchiveManifest manifest; 705 706 // Generate a bad version number. 707 manifest.set_minor_version(DeltaPerformer::kSupportedMinorPayloadVersion + 708 10000); 709 // Mark the manifest as a delta payload by setting old_rootfs_info. 710 manifest.mutable_old_rootfs_info(); 711 712 RunManifestValidation(manifest, 713 DeltaPerformer::kSupportedMajorPayloadVersion, 714 InstallPayloadType::kDelta, 715 ErrorCode::kUnsupportedMinorPayloadVersion); 716 } 717 718 TEST_F(DeltaPerformerTest, BrilloMetadataSignatureSizeTest) { 719 EXPECT_TRUE(performer_.Write(kDeltaMagic, sizeof(kDeltaMagic))); 720 721 uint64_t major_version = htobe64(kBrilloMajorPayloadVersion); 722 EXPECT_TRUE(performer_.Write(&major_version, 8)); 723 724 uint64_t manifest_size = rand() % 256; 725 uint64_t manifest_size_be = htobe64(manifest_size); 726 EXPECT_TRUE(performer_.Write(&manifest_size_be, 8)); 727 728 uint32_t metadata_signature_size = rand() % 256; 729 uint32_t metadata_signature_size_be = htobe32(metadata_signature_size); 730 EXPECT_TRUE(performer_.Write(&metadata_signature_size_be, 4)); 731 732 EXPECT_LT(performer_.Close(), 0); 733 734 EXPECT_TRUE(performer_.IsHeaderParsed()); 735 EXPECT_EQ(kBrilloMajorPayloadVersion, performer_.GetMajorVersion()); 736 uint64_t manifest_offset; 737 EXPECT_TRUE(performer_.GetManifestOffset(&manifest_offset)); 738 EXPECT_EQ(24U, manifest_offset); // 4 + 8 + 8 + 4 739 EXPECT_EQ(manifest_offset + manifest_size, performer_.GetMetadataSize()); 740 EXPECT_EQ(metadata_signature_size, performer_.metadata_signature_size_); 741 } 742 743 TEST_F(DeltaPerformerTest, BrilloVerifyMetadataSignatureTest) { 744 brillo::Blob payload_data = GeneratePayload({}, {}, true, 745 kBrilloMajorPayloadVersion, 746 kSourceMinorPayloadVersion); 747 install_plan_.hash_checks_mandatory = true; 748 // Just set these value so that we can use ValidateMetadataSignature directly. 749 performer_.major_payload_version_ = kBrilloMajorPayloadVersion; 750 performer_.metadata_size_ = install_plan_.metadata_size; 751 uint64_t signature_length; 752 EXPECT_TRUE(PayloadSigner::SignatureBlobLength( 753 {GetBuildArtifactsPath(kUnittestPrivateKeyPath)}, &signature_length)); 754 performer_.metadata_signature_size_ = signature_length; 755 performer_.set_public_key_path(GetBuildArtifactsPath(kUnittestPublicKeyPath)); 756 EXPECT_EQ(ErrorCode::kSuccess, 757 performer_.ValidateMetadataSignature(payload_data)); 758 } 759 760 TEST_F(DeltaPerformerTest, BadDeltaMagicTest) { 761 EXPECT_TRUE(performer_.Write("junk", 4)); 762 EXPECT_FALSE(performer_.Write("morejunk", 8)); 763 EXPECT_LT(performer_.Close(), 0); 764 } 765 766 TEST_F(DeltaPerformerTest, MissingMandatoryMetadataSizeTest) { 767 DoMetadataSizeTest(0, 75456, true); 768 } 769 770 TEST_F(DeltaPerformerTest, MissingNonMandatoryMetadataSizeTest) { 771 DoMetadataSizeTest(0, 123456, false); 772 } 773 774 TEST_F(DeltaPerformerTest, InvalidMandatoryMetadataSizeTest) { 775 DoMetadataSizeTest(13000, 140000, true); 776 } 777 778 TEST_F(DeltaPerformerTest, InvalidNonMandatoryMetadataSizeTest) { 779 DoMetadataSizeTest(40000, 50000, false); 780 } 781 782 TEST_F(DeltaPerformerTest, ValidMandatoryMetadataSizeTest) { 783 DoMetadataSizeTest(85376, 85376, true); 784 } 785 786 TEST_F(DeltaPerformerTest, MandatoryEmptyMetadataSignatureTest) { 787 DoMetadataSignatureTest(kEmptyMetadataSignature, true, true); 788 } 789 790 TEST_F(DeltaPerformerTest, NonMandatoryEmptyMetadataSignatureTest) { 791 DoMetadataSignatureTest(kEmptyMetadataSignature, true, false); 792 } 793 794 TEST_F(DeltaPerformerTest, MandatoryInvalidMetadataSignatureTest) { 795 DoMetadataSignatureTest(kInvalidMetadataSignature, true, true); 796 } 797 798 TEST_F(DeltaPerformerTest, NonMandatoryInvalidMetadataSignatureTest) { 799 DoMetadataSignatureTest(kInvalidMetadataSignature, true, false); 800 } 801 802 TEST_F(DeltaPerformerTest, MandatoryValidMetadataSignature1Test) { 803 DoMetadataSignatureTest(kValidMetadataSignature, false, true); 804 } 805 806 TEST_F(DeltaPerformerTest, MandatoryValidMetadataSignature2Test) { 807 DoMetadataSignatureTest(kValidMetadataSignature, true, true); 808 } 809 810 TEST_F(DeltaPerformerTest, NonMandatoryValidMetadataSignatureTest) { 811 DoMetadataSignatureTest(kValidMetadataSignature, true, false); 812 } 813 814 TEST_F(DeltaPerformerTest, UsePublicKeyFromResponse) { 815 base::FilePath key_path; 816 817 // The result of the GetPublicKeyResponse() method is based on three things 818 // 819 // 1. Whether it's an official build; and 820 // 2. Whether the Public RSA key to be used is in the root filesystem; and 821 // 3. Whether the response has a public key 822 // 823 // We test all eight combinations to ensure that we only use the 824 // public key in the response if 825 // 826 // a. it's not an official build; and 827 // b. there is no key in the root filesystem. 828 829 base::ScopedTempDir temp_dir; 830 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 831 string non_existing_file = temp_dir.path().Append("non-existing").value(); 832 string existing_file = temp_dir.path().Append("existing").value(); 833 EXPECT_EQ(0, System(base::StringPrintf("touch %s", existing_file.c_str()))); 834 835 // Non-official build, non-existing public-key, key in response -> true 836 fake_hardware_.SetIsOfficialBuild(false); 837 performer_.public_key_path_ = non_existing_file; 838 install_plan_.public_key_rsa = "VGVzdAo="; // result of 'echo "Test" | base64' 839 EXPECT_TRUE(performer_.GetPublicKeyFromResponse(&key_path)); 840 EXPECT_FALSE(key_path.empty()); 841 EXPECT_EQ(unlink(key_path.value().c_str()), 0); 842 // Same with official build -> false 843 fake_hardware_.SetIsOfficialBuild(true); 844 EXPECT_FALSE(performer_.GetPublicKeyFromResponse(&key_path)); 845 846 // Non-official build, existing public-key, key in response -> false 847 fake_hardware_.SetIsOfficialBuild(false); 848 performer_.public_key_path_ = existing_file; 849 install_plan_.public_key_rsa = "VGVzdAo="; // result of 'echo "Test" | base64' 850 EXPECT_FALSE(performer_.GetPublicKeyFromResponse(&key_path)); 851 // Same with official build -> false 852 fake_hardware_.SetIsOfficialBuild(true); 853 EXPECT_FALSE(performer_.GetPublicKeyFromResponse(&key_path)); 854 855 // Non-official build, non-existing public-key, no key in response -> false 856 fake_hardware_.SetIsOfficialBuild(false); 857 performer_.public_key_path_ = non_existing_file; 858 install_plan_.public_key_rsa = ""; 859 EXPECT_FALSE(performer_.GetPublicKeyFromResponse(&key_path)); 860 // Same with official build -> false 861 fake_hardware_.SetIsOfficialBuild(true); 862 EXPECT_FALSE(performer_.GetPublicKeyFromResponse(&key_path)); 863 864 // Non-official build, existing public-key, no key in response -> false 865 fake_hardware_.SetIsOfficialBuild(false); 866 performer_.public_key_path_ = existing_file; 867 install_plan_.public_key_rsa = ""; 868 EXPECT_FALSE(performer_.GetPublicKeyFromResponse(&key_path)); 869 // Same with official build -> false 870 fake_hardware_.SetIsOfficialBuild(true); 871 EXPECT_FALSE(performer_.GetPublicKeyFromResponse(&key_path)); 872 873 // Non-official build, non-existing public-key, key in response 874 // but invalid base64 -> false 875 fake_hardware_.SetIsOfficialBuild(false); 876 performer_.public_key_path_ = non_existing_file; 877 install_plan_.public_key_rsa = "not-valid-base64"; 878 EXPECT_FALSE(performer_.GetPublicKeyFromResponse(&key_path)); 879 } 880 881 TEST_F(DeltaPerformerTest, ConfVersionsMatch) { 882 // Test that the versions in update_engine.conf that is installed to the 883 // image match the supported delta versions in the update engine. 884 uint32_t minor_version; 885 brillo::KeyValueStore store; 886 EXPECT_TRUE(store.Load(GetBuildArtifactsPath().Append("update_engine.conf"))); 887 EXPECT_TRUE(utils::GetMinorVersion(store, &minor_version)); 888 EXPECT_EQ(DeltaPerformer::kSupportedMinorPayloadVersion, minor_version); 889 890 string major_version_str; 891 uint64_t major_version; 892 EXPECT_TRUE(store.GetString("PAYLOAD_MAJOR_VERSION", &major_version_str)); 893 EXPECT_TRUE(base::StringToUint64(major_version_str, &major_version)); 894 EXPECT_EQ(DeltaPerformer::kSupportedMajorPayloadVersion, major_version); 895 } 896 897 // Test that we recognize our own zlib compressor implementation as supported. 898 // All other equivalent implementations should be added to 899 // kCompatibleZlibFingerprint. 900 TEST_F(DeltaPerformerTest, ZlibFingerprintMatch) { 901 string fingerprint; 902 #ifdef __ANDROID__ 903 const std::string kZlibFingerprintPath = 904 test_utils::GetBuildArtifactsPath("zlib_fingerprint"); 905 #else 906 const std::string kZlibFingerprintPath = "/etc/zlib_fingerprint"; 907 #endif // __ANDROID__ 908 EXPECT_TRUE(base::ReadFileToString(base::FilePath(kZlibFingerprintPath), 909 &fingerprint)); 910 EXPECT_TRUE(utils::IsZlibCompatible(fingerprint)); 911 } 912 913 } // namespace chromeos_update_engine 914