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 <inttypes.h> 20 #include <sys/mount.h> 21 22 #include <algorithm> 23 #include <string> 24 #include <vector> 25 26 #include <base/files/file_path.h> 27 #include <base/files/file_util.h> 28 #include <base/strings/string_util.h> 29 #include <base/strings/stringprintf.h> 30 #include <google/protobuf/repeated_field.h> 31 #include <gtest/gtest.h> 32 #include <openssl/pem.h> 33 34 #include "update_engine/common/constants.h" 35 #include "update_engine/common/fake_boot_control.h" 36 #include "update_engine/common/fake_hardware.h" 37 #include "update_engine/common/mock_prefs.h" 38 #include "update_engine/common/test_utils.h" 39 #include "update_engine/common/utils.h" 40 #include "update_engine/payload_consumer/mock_download_action.h" 41 #include "update_engine/payload_consumer/payload_constants.h" 42 #include "update_engine/payload_consumer/payload_verifier.h" 43 #include "update_engine/payload_generator/delta_diff_generator.h" 44 #include "update_engine/payload_generator/payload_signer.h" 45 #include "update_engine/update_metadata.pb.h" 46 47 namespace chromeos_update_engine { 48 49 using std::string; 50 using std::vector; 51 using test_utils::GetBuildArtifactsPath; 52 using test_utils::ScopedLoopMounter; 53 using test_utils::System; 54 using test_utils::kRandomString; 55 using testing::Return; 56 using testing::_; 57 58 extern const char* kUnittestPrivateKeyPath; 59 extern const char* kUnittestPublicKeyPath; 60 extern const char* kUnittestPrivateKey2Path; 61 extern const char* kUnittestPublicKey2Path; 62 63 static const uint32_t kDefaultKernelSize = 4096; // Something small for a test 64 static const uint8_t kNewData[] = {'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 65 'n', 'e', 'w', ' ', 'd', 'a', 't', 'a', '.'}; 66 67 namespace { 68 struct DeltaState { 69 string a_img; 70 string b_img; 71 string result_img; 72 size_t image_size; 73 74 string delta_path; 75 uint64_t metadata_size; 76 77 string old_kernel; 78 brillo::Blob old_kernel_data; 79 80 string new_kernel; 81 brillo::Blob new_kernel_data; 82 83 string result_kernel; 84 brillo::Blob result_kernel_data; 85 size_t kernel_size; 86 87 // The InstallPlan referenced by the DeltaPerformer. This needs to outlive 88 // the DeltaPerformer. 89 InstallPlan install_plan; 90 91 // The in-memory copy of delta file. 92 brillo::Blob delta; 93 94 // Mock and fake instances used by the delta performer. 95 FakeBootControl fake_boot_control_; 96 FakeHardware fake_hardware_; 97 MockDownloadActionDelegate mock_delegate_; 98 }; 99 100 enum SignatureTest { 101 kSignatureNone, // No payload signing. 102 kSignatureGenerator, // Sign the payload at generation time. 103 kSignatureGenerated, // Sign the payload after it's generated. 104 kSignatureGeneratedPlaceholder, // Insert placeholder signatures, then real. 105 kSignatureGeneratedPlaceholderMismatch, // Insert a wrong sized placeholder. 106 kSignatureGeneratedShell, // Sign the generated payload through shell cmds. 107 kSignatureGeneratedShellBadKey, // Sign with a bad key through shell cmds. 108 kSignatureGeneratedShellRotateCl1, // Rotate key, test client v1 109 kSignatureGeneratedShellRotateCl2, // Rotate key, test client v2 110 }; 111 112 enum OperationHashTest { 113 kInvalidOperationData, 114 kValidOperationData, 115 }; 116 117 } // namespace 118 119 class DeltaPerformerIntegrationTest : public ::testing::Test { 120 public: 121 static void SetSupportedVersion(DeltaPerformer* performer, 122 uint64_t minor_version) { 123 performer->supported_minor_version_ = minor_version; 124 } 125 }; 126 127 static void CompareFilesByBlock(const string& a_file, const string& b_file, 128 size_t image_size) { 129 EXPECT_EQ(0U, image_size % kBlockSize); 130 131 brillo::Blob a_data, b_data; 132 EXPECT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file; 133 EXPECT_TRUE(utils::ReadFile(b_file, &b_data)) << "file failed: " << b_file; 134 135 EXPECT_GE(a_data.size(), image_size); 136 EXPECT_GE(b_data.size(), image_size); 137 for (size_t i = 0; i < image_size; i += kBlockSize) { 138 EXPECT_EQ(0U, i % kBlockSize); 139 brillo::Blob a_sub(&a_data[i], &a_data[i + kBlockSize]); 140 brillo::Blob b_sub(&b_data[i], &b_data[i + kBlockSize]); 141 EXPECT_TRUE(a_sub == b_sub) << "Block " << (i/kBlockSize) << " differs"; 142 } 143 if (::testing::Test::HasNonfatalFailure()) { 144 LOG(INFO) << "Compared filesystems with size " << image_size 145 << ", partition A " << a_file << " size: " << a_data.size() 146 << ", partition B " << b_file << " size: " << b_data.size(); 147 } 148 } 149 150 static bool WriteSparseFile(const string& path, off_t size) { 151 int fd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644); 152 TEST_AND_RETURN_FALSE_ERRNO(fd >= 0); 153 ScopedFdCloser fd_closer(&fd); 154 off_t rc = lseek(fd, size + 1, SEEK_SET); 155 TEST_AND_RETURN_FALSE_ERRNO(rc != static_cast<off_t>(-1)); 156 int return_code = ftruncate(fd, size); 157 TEST_AND_RETURN_FALSE_ERRNO(return_code == 0); 158 return true; 159 } 160 161 static bool WriteByteAtOffset(const string& path, off_t offset) { 162 int fd = open(path.c_str(), O_CREAT | O_WRONLY, 0644); 163 TEST_AND_RETURN_FALSE_ERRNO(fd >= 0); 164 ScopedFdCloser fd_closer(&fd); 165 EXPECT_TRUE(utils::PWriteAll(fd, "\0", 1, offset)); 166 return true; 167 } 168 169 static size_t GetSignatureSize(const string& private_key_path) { 170 const brillo::Blob data(1, 'x'); 171 brillo::Blob hash; 172 EXPECT_TRUE(HashCalculator::RawHashOfData(data, &hash)); 173 brillo::Blob signature; 174 EXPECT_TRUE(PayloadSigner::SignHash(hash, 175 private_key_path, 176 &signature)); 177 return signature.size(); 178 } 179 180 static bool InsertSignaturePlaceholder(int signature_size, 181 const string& payload_path, 182 uint64_t* out_metadata_size) { 183 vector<brillo::Blob> signatures; 184 signatures.push_back(brillo::Blob(signature_size, 0)); 185 186 return PayloadSigner::AddSignatureToPayload( 187 payload_path, 188 signatures, 189 {}, 190 payload_path, 191 out_metadata_size); 192 } 193 194 static void SignGeneratedPayload(const string& payload_path, 195 uint64_t* out_metadata_size) { 196 string private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath); 197 int signature_size = GetSignatureSize(private_key_path); 198 brillo::Blob hash; 199 ASSERT_TRUE(PayloadSigner::HashPayloadForSigning( 200 payload_path, {signature_size}, &hash, nullptr)); 201 brillo::Blob signature; 202 ASSERT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature)); 203 ASSERT_TRUE(PayloadSigner::AddSignatureToPayload( 204 payload_path, {signature}, {}, payload_path, out_metadata_size)); 205 EXPECT_TRUE(PayloadSigner::VerifySignedPayload( 206 payload_path, GetBuildArtifactsPath(kUnittestPublicKeyPath))); 207 } 208 209 static void SignGeneratedShellPayload(SignatureTest signature_test, 210 const string& payload_path) { 211 string private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath); 212 if (signature_test == kSignatureGeneratedShellBadKey) { 213 ASSERT_TRUE(utils::MakeTempFile("key.XXXXXX", 214 &private_key_path, 215 nullptr)); 216 } else { 217 ASSERT_TRUE(signature_test == kSignatureGeneratedShell || 218 signature_test == kSignatureGeneratedShellRotateCl1 || 219 signature_test == kSignatureGeneratedShellRotateCl2); 220 } 221 ScopedPathUnlinker key_unlinker(private_key_path); 222 key_unlinker.set_should_remove(signature_test == 223 kSignatureGeneratedShellBadKey); 224 // Generates a new private key that will not match the public key. 225 if (signature_test == kSignatureGeneratedShellBadKey) { 226 LOG(INFO) << "Generating a mismatched private key."; 227 // The code below executes the equivalent of: 228 // openssl genrsa -out <private_key_path> 2048 229 RSA* rsa = RSA_new(); 230 BIGNUM* e = BN_new(); 231 EXPECT_EQ(1, BN_set_word(e, RSA_F4)); 232 EXPECT_EQ(1, RSA_generate_key_ex(rsa, 2048, e, nullptr)); 233 BN_free(e); 234 FILE* fprikey = fopen(private_key_path.c_str(), "w"); 235 EXPECT_NE(nullptr, fprikey); 236 EXPECT_EQ(1, 237 PEM_write_RSAPrivateKey( 238 fprikey, rsa, nullptr, nullptr, 0, nullptr, nullptr)); 239 fclose(fprikey); 240 RSA_free(rsa); 241 } 242 int signature_size = GetSignatureSize(private_key_path); 243 string hash_file; 244 ASSERT_TRUE(utils::MakeTempFile("hash.XXXXXX", &hash_file, nullptr)); 245 ScopedPathUnlinker hash_unlinker(hash_file); 246 string signature_size_string; 247 if (signature_test == kSignatureGeneratedShellRotateCl1 || 248 signature_test == kSignatureGeneratedShellRotateCl2) 249 signature_size_string = base::StringPrintf("%d:%d", 250 signature_size, signature_size); 251 else 252 signature_size_string = base::StringPrintf("%d", signature_size); 253 string delta_generator_path = GetBuildArtifactsPath("delta_generator"); 254 ASSERT_EQ(0, 255 System(base::StringPrintf( 256 "%s -in_file=%s -signature_size=%s -out_hash_file=%s", 257 delta_generator_path.c_str(), 258 payload_path.c_str(), 259 signature_size_string.c_str(), 260 hash_file.c_str()))); 261 262 // Sign the hash 263 brillo::Blob hash, signature; 264 ASSERT_TRUE(utils::ReadFile(hash_file, &hash)); 265 ASSERT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature)); 266 267 string sig_file; 268 ASSERT_TRUE(utils::MakeTempFile("signature.XXXXXX", &sig_file, nullptr)); 269 ScopedPathUnlinker sig_unlinker(sig_file); 270 ASSERT_TRUE(test_utils::WriteFileVector(sig_file, signature)); 271 272 string sig_file2; 273 ASSERT_TRUE(utils::MakeTempFile("signature.XXXXXX", &sig_file2, nullptr)); 274 ScopedPathUnlinker sig2_unlinker(sig_file2); 275 if (signature_test == kSignatureGeneratedShellRotateCl1 || 276 signature_test == kSignatureGeneratedShellRotateCl2) { 277 ASSERT_TRUE(PayloadSigner::SignHash( 278 hash, GetBuildArtifactsPath(kUnittestPrivateKey2Path), &signature)); 279 ASSERT_TRUE(test_utils::WriteFileVector(sig_file2, signature)); 280 // Append second sig file to first path 281 sig_file += ":" + sig_file2; 282 } 283 284 ASSERT_EQ(0, 285 System(base::StringPrintf( 286 "%s -in_file=%s -signature_file=%s -out_file=%s", 287 delta_generator_path.c_str(), 288 payload_path.c_str(), 289 sig_file.c_str(), 290 payload_path.c_str()))); 291 int verify_result = System(base::StringPrintf( 292 "%s -in_file=%s -public_key=%s -public_key_version=%d", 293 delta_generator_path.c_str(), 294 payload_path.c_str(), 295 (signature_test == kSignatureGeneratedShellRotateCl2 296 ? GetBuildArtifactsPath(kUnittestPublicKey2Path) 297 : GetBuildArtifactsPath(kUnittestPublicKeyPath)) 298 .c_str(), 299 signature_test == kSignatureGeneratedShellRotateCl2 ? 2 : 1)); 300 if (signature_test == kSignatureGeneratedShellBadKey) { 301 ASSERT_NE(0, verify_result); 302 } else { 303 ASSERT_EQ(0, verify_result); 304 } 305 } 306 307 static void GenerateDeltaFile(bool full_kernel, 308 bool full_rootfs, 309 bool noop, 310 ssize_t chunk_size, 311 SignatureTest signature_test, 312 DeltaState *state, 313 uint32_t minor_version) { 314 EXPECT_TRUE(utils::MakeTempFile("a_img.XXXXXX", &state->a_img, nullptr)); 315 EXPECT_TRUE(utils::MakeTempFile("b_img.XXXXXX", &state->b_img, nullptr)); 316 317 // result_img is used in minor version 2. Instead of applying the update 318 // in-place on A, we apply it to a new image, result_img. 319 EXPECT_TRUE( 320 utils::MakeTempFile("result_img.XXXXXX", &state->result_img, nullptr)); 321 322 EXPECT_TRUE( 323 base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"), 324 base::FilePath(state->a_img))); 325 326 state->image_size = utils::FileSize(state->a_img); 327 328 // Create ImageInfo A & B 329 ImageInfo old_image_info; 330 ImageInfo new_image_info; 331 332 if (!full_rootfs) { 333 old_image_info.set_channel("src-channel"); 334 old_image_info.set_board("src-board"); 335 old_image_info.set_version("src-version"); 336 old_image_info.set_key("src-key"); 337 old_image_info.set_build_channel("src-build-channel"); 338 old_image_info.set_build_version("src-build-version"); 339 } 340 341 new_image_info.set_channel("test-channel"); 342 new_image_info.set_board("test-board"); 343 new_image_info.set_version("test-version"); 344 new_image_info.set_key("test-key"); 345 new_image_info.set_build_channel("test-build-channel"); 346 new_image_info.set_build_version("test-build-version"); 347 348 // Make some changes to the A image. 349 { 350 string a_mnt; 351 ScopedLoopMounter b_mounter(state->a_img, &a_mnt, 0); 352 353 brillo::Blob hardtocompress; 354 while (hardtocompress.size() < 3 * kBlockSize) { 355 hardtocompress.insert(hardtocompress.end(), 356 std::begin(kRandomString), std::end(kRandomString)); 357 } 358 EXPECT_TRUE(utils::WriteFile(base::StringPrintf("%s/hardtocompress", 359 a_mnt.c_str()).c_str(), 360 hardtocompress.data(), 361 hardtocompress.size())); 362 363 brillo::Blob zeros(16 * 1024, 0); 364 EXPECT_EQ(static_cast<int>(zeros.size()), 365 base::WriteFile(base::FilePath(base::StringPrintf( 366 "%s/move-to-sparse", a_mnt.c_str())), 367 reinterpret_cast<const char*>(zeros.data()), 368 zeros.size())); 369 370 EXPECT_TRUE( 371 WriteSparseFile(base::StringPrintf("%s/move-from-sparse", 372 a_mnt.c_str()), 16 * 1024)); 373 374 EXPECT_TRUE(WriteByteAtOffset( 375 base::StringPrintf("%s/move-semi-sparse", a_mnt.c_str()), 4096)); 376 377 // Write 1 MiB of 0xff to try to catch the case where writing a bsdiff 378 // patch fails to zero out the final block. 379 brillo::Blob ones(1024 * 1024, 0xff); 380 EXPECT_TRUE(utils::WriteFile(base::StringPrintf("%s/ones", 381 a_mnt.c_str()).c_str(), 382 ones.data(), 383 ones.size())); 384 } 385 386 if (noop) { 387 EXPECT_TRUE(base::CopyFile(base::FilePath(state->a_img), 388 base::FilePath(state->b_img))); 389 old_image_info = new_image_info; 390 } else { 391 if (minor_version == kSourceMinorPayloadVersion) { 392 // Create a result image with image_size bytes of garbage. 393 brillo::Blob ones(state->image_size, 0xff); 394 EXPECT_TRUE(utils::WriteFile(state->result_img.c_str(), 395 ones.data(), 396 ones.size())); 397 EXPECT_EQ(utils::FileSize(state->a_img), 398 utils::FileSize(state->result_img)); 399 } 400 401 EXPECT_TRUE( 402 base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"), 403 base::FilePath(state->b_img))); 404 405 // Make some changes to the B image. 406 string b_mnt; 407 ScopedLoopMounter b_mounter(state->b_img, &b_mnt, 0); 408 base::FilePath mnt_path(b_mnt); 409 410 EXPECT_TRUE(base::CopyFile(mnt_path.Append("regular-small"), 411 mnt_path.Append("regular-small2"))); 412 EXPECT_TRUE(base::DeleteFile(mnt_path.Append("regular-small"), false)); 413 EXPECT_TRUE(base::Move(mnt_path.Append("regular-small2"), 414 mnt_path.Append("regular-small"))); 415 EXPECT_TRUE( 416 test_utils::WriteFileString(mnt_path.Append("foo").value(), "foo")); 417 EXPECT_EQ(0, base::WriteFile(mnt_path.Append("emptyfile"), "", 0)); 418 419 EXPECT_TRUE( 420 WriteSparseFile(mnt_path.Append("fullsparse").value(), 1024 * 1024)); 421 EXPECT_TRUE( 422 WriteSparseFile(mnt_path.Append("move-to-sparse").value(), 16 * 1024)); 423 424 brillo::Blob zeros(16 * 1024, 0); 425 EXPECT_EQ(static_cast<int>(zeros.size()), 426 base::WriteFile(mnt_path.Append("move-from-sparse"), 427 reinterpret_cast<const char*>(zeros.data()), 428 zeros.size())); 429 430 EXPECT_TRUE( 431 WriteByteAtOffset(mnt_path.Append("move-semi-sparse").value(), 4096)); 432 EXPECT_TRUE(WriteByteAtOffset(mnt_path.Append("partsparse").value(), 4096)); 433 434 EXPECT_TRUE( 435 base::CopyFile(mnt_path.Append("regular-16k"), mnt_path.Append("tmp"))); 436 EXPECT_TRUE(base::Move(mnt_path.Append("tmp"), 437 mnt_path.Append("link-hard-regular-16k"))); 438 439 EXPECT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink"), false)); 440 EXPECT_TRUE(test_utils::WriteFileString( 441 mnt_path.Append("link-short_symlink").value(), "foobar")); 442 443 brillo::Blob hardtocompress; 444 while (hardtocompress.size() < 3 * kBlockSize) { 445 hardtocompress.insert(hardtocompress.end(), 446 std::begin(kRandomString), std::end(kRandomString)); 447 } 448 EXPECT_TRUE(utils::WriteFile(base::StringPrintf("%s/hardtocompress", 449 b_mnt.c_str()).c_str(), 450 hardtocompress.data(), 451 hardtocompress.size())); 452 } 453 454 string old_kernel; 455 EXPECT_TRUE(utils::MakeTempFile("old_kernel.XXXXXX", 456 &state->old_kernel, 457 nullptr)); 458 459 string new_kernel; 460 EXPECT_TRUE(utils::MakeTempFile("new_kernel.XXXXXX", 461 &state->new_kernel, 462 nullptr)); 463 464 string result_kernel; 465 EXPECT_TRUE(utils::MakeTempFile("result_kernel.XXXXXX", 466 &state->result_kernel, 467 nullptr)); 468 469 state->kernel_size = kDefaultKernelSize; 470 state->old_kernel_data.resize(kDefaultKernelSize); 471 state->new_kernel_data.resize(state->old_kernel_data.size()); 472 state->result_kernel_data.resize(state->old_kernel_data.size()); 473 test_utils::FillWithData(&state->old_kernel_data); 474 test_utils::FillWithData(&state->new_kernel_data); 475 test_utils::FillWithData(&state->result_kernel_data); 476 477 // change the new kernel data 478 std::copy(std::begin(kNewData), std::end(kNewData), 479 state->new_kernel_data.begin()); 480 481 if (noop) { 482 state->old_kernel_data = state->new_kernel_data; 483 } 484 485 // Write kernels to disk 486 EXPECT_TRUE(utils::WriteFile(state->old_kernel.c_str(), 487 state->old_kernel_data.data(), 488 state->old_kernel_data.size())); 489 EXPECT_TRUE(utils::WriteFile(state->new_kernel.c_str(), 490 state->new_kernel_data.data(), 491 state->new_kernel_data.size())); 492 EXPECT_TRUE(utils::WriteFile(state->result_kernel.c_str(), 493 state->result_kernel_data.data(), 494 state->result_kernel_data.size())); 495 496 EXPECT_TRUE(utils::MakeTempFile("delta.XXXXXX", 497 &state->delta_path, 498 nullptr)); 499 LOG(INFO) << "delta path: " << state->delta_path; 500 { 501 const string private_key = 502 signature_test == kSignatureGenerator 503 ? GetBuildArtifactsPath(kUnittestPrivateKeyPath) 504 : ""; 505 506 PayloadGenerationConfig payload_config; 507 payload_config.is_delta = !full_rootfs; 508 payload_config.hard_chunk_size = chunk_size; 509 payload_config.rootfs_partition_size = kRootFSPartitionSize; 510 payload_config.version.major = kChromeOSMajorPayloadVersion; 511 payload_config.version.minor = minor_version; 512 if (!full_rootfs) { 513 payload_config.source.partitions.emplace_back(kLegacyPartitionNameRoot); 514 payload_config.source.partitions.emplace_back(kLegacyPartitionNameKernel); 515 payload_config.source.partitions.front().path = state->a_img; 516 if (!full_kernel) 517 payload_config.source.partitions.back().path = state->old_kernel; 518 payload_config.source.image_info = old_image_info; 519 EXPECT_TRUE(payload_config.source.LoadImageSize()); 520 for (PartitionConfig& part : payload_config.source.partitions) 521 EXPECT_TRUE(part.OpenFilesystem()); 522 } else { 523 if (payload_config.hard_chunk_size == -1) 524 // Use 1 MiB chunk size for the full unittests. 525 payload_config.hard_chunk_size = 1024 * 1024; 526 } 527 payload_config.target.partitions.emplace_back(kLegacyPartitionNameRoot); 528 payload_config.target.partitions.back().path = state->b_img; 529 payload_config.target.partitions.emplace_back(kLegacyPartitionNameKernel); 530 payload_config.target.partitions.back().path = state->new_kernel; 531 payload_config.target.image_info = new_image_info; 532 EXPECT_TRUE(payload_config.target.LoadImageSize()); 533 for (PartitionConfig& part : payload_config.target.partitions) 534 EXPECT_TRUE(part.OpenFilesystem()); 535 536 EXPECT_TRUE(payload_config.Validate()); 537 EXPECT_TRUE( 538 GenerateUpdatePayloadFile( 539 payload_config, 540 state->delta_path, 541 private_key, 542 &state->metadata_size)); 543 } 544 // Extend the "partitions" holding the file system a bit. 545 EXPECT_EQ(0, HANDLE_EINTR(truncate(state->a_img.c_str(), 546 state->image_size + 1024 * 1024))); 547 EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024), 548 utils::FileSize(state->a_img)); 549 EXPECT_EQ(0, HANDLE_EINTR(truncate(state->b_img.c_str(), 550 state->image_size + 1024 * 1024))); 551 EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024), 552 utils::FileSize(state->b_img)); 553 554 if (signature_test == kSignatureGeneratedPlaceholder || 555 signature_test == kSignatureGeneratedPlaceholderMismatch) { 556 int signature_size = 557 GetSignatureSize(GetBuildArtifactsPath(kUnittestPrivateKeyPath)); 558 LOG(INFO) << "Inserting placeholder signature."; 559 ASSERT_TRUE(InsertSignaturePlaceholder(signature_size, state->delta_path, 560 &state->metadata_size)); 561 562 if (signature_test == kSignatureGeneratedPlaceholderMismatch) { 563 signature_size -= 1; 564 LOG(INFO) << "Inserting mismatched placeholder signature."; 565 ASSERT_FALSE(InsertSignaturePlaceholder(signature_size, state->delta_path, 566 &state->metadata_size)); 567 return; 568 } 569 } 570 571 if (signature_test == kSignatureGenerated || 572 signature_test == kSignatureGeneratedPlaceholder || 573 signature_test == kSignatureGeneratedPlaceholderMismatch) { 574 // Generate the signed payload and update the metadata size in state to 575 // reflect the new size after adding the signature operation to the 576 // manifest. 577 LOG(INFO) << "Signing payload."; 578 SignGeneratedPayload(state->delta_path, &state->metadata_size); 579 } else if (signature_test == kSignatureGeneratedShell || 580 signature_test == kSignatureGeneratedShellBadKey || 581 signature_test == kSignatureGeneratedShellRotateCl1 || 582 signature_test == kSignatureGeneratedShellRotateCl2) { 583 SignGeneratedShellPayload(signature_test, state->delta_path); 584 } 585 } 586 587 static void ApplyDeltaFile(bool full_kernel, bool full_rootfs, bool noop, 588 SignatureTest signature_test, DeltaState* state, 589 bool hash_checks_mandatory, 590 OperationHashTest op_hash_test, 591 DeltaPerformer** performer, 592 uint32_t minor_version) { 593 // Check the metadata. 594 { 595 DeltaArchiveManifest manifest; 596 EXPECT_TRUE(PayloadSigner::LoadPayloadMetadata(state->delta_path, 597 nullptr, 598 &manifest, 599 nullptr, 600 &state->metadata_size, 601 nullptr)); 602 LOG(INFO) << "Metadata size: " << state->metadata_size; 603 EXPECT_TRUE(utils::ReadFile(state->delta_path, &state->delta)); 604 605 if (signature_test == kSignatureNone) { 606 EXPECT_FALSE(manifest.has_signatures_offset()); 607 EXPECT_FALSE(manifest.has_signatures_size()); 608 } else { 609 EXPECT_TRUE(manifest.has_signatures_offset()); 610 EXPECT_TRUE(manifest.has_signatures_size()); 611 Signatures sigs_message; 612 EXPECT_TRUE(sigs_message.ParseFromArray( 613 &state->delta[state->metadata_size + manifest.signatures_offset()], 614 manifest.signatures_size())); 615 if (signature_test == kSignatureGeneratedShellRotateCl1 || 616 signature_test == kSignatureGeneratedShellRotateCl2) 617 EXPECT_EQ(2, sigs_message.signatures_size()); 618 else 619 EXPECT_EQ(1, sigs_message.signatures_size()); 620 const Signatures_Signature& signature = sigs_message.signatures(0); 621 EXPECT_EQ(1U, signature.version()); 622 623 uint64_t expected_sig_data_length = 0; 624 vector<string> key_paths{GetBuildArtifactsPath(kUnittestPrivateKeyPath)}; 625 if (signature_test == kSignatureGeneratedShellRotateCl1 || 626 signature_test == kSignatureGeneratedShellRotateCl2) { 627 key_paths.push_back(GetBuildArtifactsPath(kUnittestPrivateKey2Path)); 628 } 629 EXPECT_TRUE(PayloadSigner::SignatureBlobLength( 630 key_paths, 631 &expected_sig_data_length)); 632 EXPECT_EQ(expected_sig_data_length, manifest.signatures_size()); 633 EXPECT_FALSE(signature.data().empty()); 634 } 635 636 if (noop) { 637 EXPECT_EQ(0, manifest.install_operations_size()); 638 EXPECT_EQ(1, manifest.kernel_install_operations_size()); 639 } 640 641 if (full_kernel) { 642 EXPECT_FALSE(manifest.has_old_kernel_info()); 643 } else { 644 EXPECT_EQ(state->old_kernel_data.size(), 645 manifest.old_kernel_info().size()); 646 EXPECT_FALSE(manifest.old_kernel_info().hash().empty()); 647 } 648 649 EXPECT_EQ(manifest.new_image_info().channel(), "test-channel"); 650 EXPECT_EQ(manifest.new_image_info().board(), "test-board"); 651 EXPECT_EQ(manifest.new_image_info().version(), "test-version"); 652 EXPECT_EQ(manifest.new_image_info().key(), "test-key"); 653 EXPECT_EQ(manifest.new_image_info().build_channel(), "test-build-channel"); 654 EXPECT_EQ(manifest.new_image_info().build_version(), "test-build-version"); 655 656 if (!full_rootfs) { 657 if (noop) { 658 EXPECT_EQ(manifest.old_image_info().channel(), "test-channel"); 659 EXPECT_EQ(manifest.old_image_info().board(), "test-board"); 660 EXPECT_EQ(manifest.old_image_info().version(), "test-version"); 661 EXPECT_EQ(manifest.old_image_info().key(), "test-key"); 662 EXPECT_EQ(manifest.old_image_info().build_channel(), 663 "test-build-channel"); 664 EXPECT_EQ(manifest.old_image_info().build_version(), 665 "test-build-version"); 666 } else { 667 EXPECT_EQ(manifest.old_image_info().channel(), "src-channel"); 668 EXPECT_EQ(manifest.old_image_info().board(), "src-board"); 669 EXPECT_EQ(manifest.old_image_info().version(), "src-version"); 670 EXPECT_EQ(manifest.old_image_info().key(), "src-key"); 671 EXPECT_EQ(manifest.old_image_info().build_channel(), 672 "src-build-channel"); 673 EXPECT_EQ(manifest.old_image_info().build_version(), 674 "src-build-version"); 675 } 676 } 677 678 679 if (full_rootfs) { 680 EXPECT_FALSE(manifest.has_old_rootfs_info()); 681 EXPECT_FALSE(manifest.has_old_image_info()); 682 EXPECT_TRUE(manifest.has_new_image_info()); 683 } else { 684 EXPECT_EQ(state->image_size, manifest.old_rootfs_info().size()); 685 EXPECT_FALSE(manifest.old_rootfs_info().hash().empty()); 686 } 687 688 EXPECT_EQ(state->new_kernel_data.size(), manifest.new_kernel_info().size()); 689 EXPECT_EQ(state->image_size, manifest.new_rootfs_info().size()); 690 691 EXPECT_FALSE(manifest.new_kernel_info().hash().empty()); 692 EXPECT_FALSE(manifest.new_rootfs_info().hash().empty()); 693 } 694 695 MockPrefs prefs; 696 EXPECT_CALL(prefs, SetInt64(kPrefsManifestMetadataSize, 697 state->metadata_size)).WillOnce(Return(true)); 698 EXPECT_CALL(prefs, SetInt64(kPrefsManifestSignatureSize, 0)) 699 .WillOnce(Return(true)); 700 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextOperation, _)) 701 .WillRepeatedly(Return(true)); 702 EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextOperation, _)) 703 .WillOnce(Return(false)); 704 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataOffset, _)) 705 .WillRepeatedly(Return(true)); 706 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataLength, _)) 707 .WillRepeatedly(Return(true)); 708 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSHA256Context, _)) 709 .WillRepeatedly(Return(true)); 710 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignedSHA256Context, _)) 711 .WillRepeatedly(Return(true)); 712 if (op_hash_test == kValidOperationData && signature_test != kSignatureNone) { 713 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignatureBlob, _)) 714 .WillOnce(Return(true)); 715 } 716 717 EXPECT_CALL(state->mock_delegate_, ShouldCancel(_)) 718 .WillRepeatedly(Return(false)); 719 720 // Update the A image in place. 721 InstallPlan* install_plan = &state->install_plan; 722 install_plan->hash_checks_mandatory = hash_checks_mandatory; 723 install_plan->payloads = {{.metadata_size = state->metadata_size, 724 .type = (full_kernel && full_rootfs) 725 ? InstallPayloadType::kFull 726 : InstallPayloadType::kDelta}}; 727 install_plan->source_slot = 0; 728 install_plan->target_slot = 1; 729 730 InstallPlan::Partition root_part; 731 root_part.name = kLegacyPartitionNameRoot; 732 733 InstallPlan::Partition kernel_part; 734 kernel_part.name = kLegacyPartitionNameKernel; 735 736 LOG(INFO) << "Setting payload metadata size in Omaha = " 737 << state->metadata_size; 738 ASSERT_TRUE(PayloadSigner::GetMetadataSignature( 739 state->delta.data(), 740 state->metadata_size, 741 GetBuildArtifactsPath(kUnittestPrivateKeyPath), 742 &install_plan->payloads[0].metadata_signature)); 743 EXPECT_FALSE(install_plan->payloads[0].metadata_signature.empty()); 744 745 *performer = new DeltaPerformer(&prefs, 746 &state->fake_boot_control_, 747 &state->fake_hardware_, 748 &state->mock_delegate_, 749 install_plan, 750 &install_plan->payloads[0], 751 false /* is_interactive */); 752 string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath); 753 EXPECT_TRUE(utils::FileExists(public_key_path.c_str())); 754 (*performer)->set_public_key_path(public_key_path); 755 DeltaPerformerIntegrationTest::SetSupportedVersion(*performer, minor_version); 756 757 EXPECT_EQ(static_cast<off_t>(state->image_size), 758 HashCalculator::RawHashOfFile( 759 state->a_img, 760 state->image_size, 761 &root_part.source_hash)); 762 EXPECT_TRUE(HashCalculator::RawHashOfData( 763 state->old_kernel_data, 764 &kernel_part.source_hash)); 765 766 // The partitions should be empty before DeltaPerformer. 767 install_plan->partitions.clear(); 768 769 // With minor version 2, we want the target to be the new image, result_img, 770 // but with version 1, we want to update A in place. 771 string target_root, target_kernel; 772 if (minor_version == kSourceMinorPayloadVersion) { 773 target_root = state->result_img; 774 target_kernel = state->result_kernel; 775 } else { 776 target_root = state->a_img; 777 target_kernel = state->old_kernel; 778 } 779 780 state->fake_boot_control_.SetPartitionDevice( 781 kLegacyPartitionNameRoot, install_plan->source_slot, state->a_img); 782 state->fake_boot_control_.SetPartitionDevice( 783 kLegacyPartitionNameKernel, install_plan->source_slot, state->old_kernel); 784 state->fake_boot_control_.SetPartitionDevice( 785 kLegacyPartitionNameRoot, install_plan->target_slot, target_root); 786 state->fake_boot_control_.SetPartitionDevice( 787 kLegacyPartitionNameKernel, install_plan->target_slot, target_kernel); 788 789 ErrorCode expected_error, actual_error; 790 bool continue_writing; 791 switch (op_hash_test) { 792 case kInvalidOperationData: { 793 // Muck with some random offset post the metadata size so that 794 // some operation hash will result in a mismatch. 795 int some_offset = state->metadata_size + 300; 796 LOG(INFO) << "Tampered value at offset: " << some_offset; 797 state->delta[some_offset]++; 798 expected_error = ErrorCode::kDownloadOperationHashMismatch; 799 continue_writing = false; 800 break; 801 } 802 803 case kValidOperationData: 804 default: 805 // no change. 806 expected_error = ErrorCode::kSuccess; 807 continue_writing = true; 808 break; 809 } 810 811 // Write at some number of bytes per operation. Arbitrarily chose 5. 812 const size_t kBytesPerWrite = 5; 813 for (size_t i = 0; i < state->delta.size(); i += kBytesPerWrite) { 814 size_t count = std::min(state->delta.size() - i, kBytesPerWrite); 815 bool write_succeeded = ((*performer)->Write(&state->delta[i], 816 count, 817 &actual_error)); 818 // Normally write_succeeded should be true every time and 819 // actual_error should be ErrorCode::kSuccess. If so, continue the loop. 820 // But if we seeded an operation hash error above, then write_succeeded 821 // will be false. The failure may happen at any operation n. So, all 822 // Writes until n-1 should succeed and the nth operation will fail with 823 // actual_error. In this case, we should bail out of the loop because 824 // we cannot proceed applying the delta. 825 if (!write_succeeded) { 826 LOG(INFO) << "Write failed. Checking if it failed with expected error"; 827 EXPECT_EQ(expected_error, actual_error); 828 if (!continue_writing) { 829 LOG(INFO) << "Cannot continue writing. Bailing out."; 830 break; 831 } 832 } 833 834 EXPECT_EQ(ErrorCode::kSuccess, actual_error); 835 } 836 837 // If we had continued all the way through, Close should succeed. 838 // Otherwise, it should fail. Check appropriately. 839 bool close_result = (*performer)->Close(); 840 if (continue_writing) 841 EXPECT_EQ(0, close_result); 842 else 843 EXPECT_LE(0, close_result); 844 } 845 846 void VerifyPayloadResult(DeltaPerformer* performer, 847 DeltaState* state, 848 ErrorCode expected_result, 849 uint32_t minor_version) { 850 if (!performer) { 851 EXPECT_TRUE(!"Skipping payload verification since performer is null."); 852 return; 853 } 854 855 int expected_times = (expected_result == ErrorCode::kSuccess) ? 1 : 0; 856 EXPECT_CALL(state->mock_delegate_, DownloadComplete()).Times(expected_times); 857 858 LOG(INFO) << "Verifying payload for expected result " << expected_result; 859 brillo::Blob expected_hash; 860 HashCalculator::RawHashOfData(state->delta, &expected_hash); 861 EXPECT_EQ(expected_result, 862 performer->VerifyPayload(expected_hash, state->delta.size())); 863 LOG(INFO) << "Verified payload."; 864 865 if (expected_result != ErrorCode::kSuccess) { 866 // no need to verify new partition if VerifyPayload failed. 867 return; 868 } 869 870 brillo::Blob updated_kernel_partition; 871 if (minor_version == kSourceMinorPayloadVersion) { 872 CompareFilesByBlock(state->result_kernel, state->new_kernel, 873 state->kernel_size); 874 CompareFilesByBlock(state->result_img, state->b_img, 875 state->image_size); 876 EXPECT_TRUE(utils::ReadFile(state->result_kernel, 877 &updated_kernel_partition)); 878 } else { 879 CompareFilesByBlock(state->old_kernel, state->new_kernel, 880 state->kernel_size); 881 CompareFilesByBlock(state->a_img, state->b_img, 882 state->image_size); 883 EXPECT_TRUE(utils::ReadFile(state->old_kernel, &updated_kernel_partition)); 884 } 885 886 ASSERT_GE(updated_kernel_partition.size(), arraysize(kNewData)); 887 EXPECT_TRUE(std::equal(std::begin(kNewData), std::end(kNewData), 888 updated_kernel_partition.begin())); 889 890 const auto& partitions = state->install_plan.partitions; 891 EXPECT_EQ(2U, partitions.size()); 892 EXPECT_EQ(kLegacyPartitionNameRoot, partitions[0].name); 893 EXPECT_EQ(kLegacyPartitionNameKernel, partitions[1].name); 894 895 EXPECT_EQ(kDefaultKernelSize, partitions[1].target_size); 896 brillo::Blob expected_new_kernel_hash; 897 EXPECT_TRUE(HashCalculator::RawHashOfData(state->new_kernel_data, 898 &expected_new_kernel_hash)); 899 EXPECT_EQ(expected_new_kernel_hash, partitions[1].target_hash); 900 901 EXPECT_EQ(state->image_size, partitions[0].target_size); 902 brillo::Blob expected_new_rootfs_hash; 903 EXPECT_EQ(static_cast<off_t>(state->image_size), 904 HashCalculator::RawHashOfFile(state->b_img, 905 state->image_size, 906 &expected_new_rootfs_hash)); 907 EXPECT_EQ(expected_new_rootfs_hash, partitions[0].target_hash); 908 } 909 910 void VerifyPayload(DeltaPerformer* performer, 911 DeltaState* state, 912 SignatureTest signature_test, 913 uint32_t minor_version) { 914 ErrorCode expected_result = ErrorCode::kSuccess; 915 switch (signature_test) { 916 case kSignatureNone: 917 expected_result = ErrorCode::kSignedDeltaPayloadExpectedError; 918 break; 919 case kSignatureGeneratedShellBadKey: 920 expected_result = ErrorCode::kDownloadPayloadPubKeyVerificationError; 921 break; 922 default: break; // appease gcc 923 } 924 925 VerifyPayloadResult(performer, state, expected_result, minor_version); 926 } 927 928 void DoSmallImageTest(bool full_kernel, bool full_rootfs, bool noop, 929 ssize_t chunk_size, 930 SignatureTest signature_test, 931 bool hash_checks_mandatory, uint32_t minor_version) { 932 DeltaState state; 933 DeltaPerformer *performer = nullptr; 934 GenerateDeltaFile(full_kernel, full_rootfs, noop, chunk_size, 935 signature_test, &state, minor_version); 936 937 ScopedPathUnlinker a_img_unlinker(state.a_img); 938 ScopedPathUnlinker b_img_unlinker(state.b_img); 939 ScopedPathUnlinker new_img_unlinker(state.result_img); 940 ScopedPathUnlinker delta_unlinker(state.delta_path); 941 ScopedPathUnlinker old_kernel_unlinker(state.old_kernel); 942 ScopedPathUnlinker new_kernel_unlinker(state.new_kernel); 943 ScopedPathUnlinker result_kernel_unlinker(state.result_kernel); 944 ApplyDeltaFile(full_kernel, full_rootfs, noop, signature_test, 945 &state, hash_checks_mandatory, kValidOperationData, 946 &performer, minor_version); 947 VerifyPayload(performer, &state, signature_test, minor_version); 948 delete performer; 949 } 950 951 void DoOperationHashMismatchTest(OperationHashTest op_hash_test, 952 bool hash_checks_mandatory) { 953 DeltaState state; 954 uint64_t minor_version = kFullPayloadMinorVersion; 955 GenerateDeltaFile(true, true, false, -1, kSignatureGenerated, &state, 956 minor_version); 957 ScopedPathUnlinker a_img_unlinker(state.a_img); 958 ScopedPathUnlinker b_img_unlinker(state.b_img); 959 ScopedPathUnlinker delta_unlinker(state.delta_path); 960 ScopedPathUnlinker old_kernel_unlinker(state.old_kernel); 961 ScopedPathUnlinker new_kernel_unlinker(state.new_kernel); 962 DeltaPerformer *performer = nullptr; 963 ApplyDeltaFile(true, true, false, kSignatureGenerated, &state, 964 hash_checks_mandatory, op_hash_test, &performer, 965 minor_version); 966 delete performer; 967 } 968 969 970 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageTest) { 971 DoSmallImageTest(false, false, false, -1, kSignatureGenerator, 972 false, kInPlaceMinorPayloadVersion); 973 } 974 975 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignaturePlaceholderTest) { 976 DoSmallImageTest(false, false, false, -1, kSignatureGeneratedPlaceholder, 977 false, kInPlaceMinorPayloadVersion); 978 } 979 980 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignaturePlaceholderMismatchTest) { 981 DeltaState state; 982 GenerateDeltaFile(false, false, false, -1, 983 kSignatureGeneratedPlaceholderMismatch, &state, 984 kInPlaceMinorPayloadVersion); 985 } 986 987 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageChunksTest) { 988 DoSmallImageTest(false, false, false, kBlockSize, kSignatureGenerator, 989 false, kInPlaceMinorPayloadVersion); 990 } 991 992 TEST(DeltaPerformerIntegrationTest, RunAsRootFullKernelSmallImageTest) { 993 DoSmallImageTest(true, false, false, -1, kSignatureGenerator, 994 false, kInPlaceMinorPayloadVersion); 995 } 996 997 TEST(DeltaPerformerIntegrationTest, RunAsRootFullSmallImageTest) { 998 DoSmallImageTest(true, true, false, -1, kSignatureGenerator, 999 true, kFullPayloadMinorVersion); 1000 } 1001 1002 TEST(DeltaPerformerIntegrationTest, RunAsRootNoopSmallImageTest) { 1003 DoSmallImageTest(false, false, true, -1, kSignatureGenerator, 1004 false, kInPlaceMinorPayloadVersion); 1005 } 1006 1007 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignNoneTest) { 1008 DoSmallImageTest(false, false, false, -1, kSignatureNone, 1009 false, kInPlaceMinorPayloadVersion); 1010 } 1011 1012 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedTest) { 1013 DoSmallImageTest(false, false, false, -1, kSignatureGenerated, 1014 true, kInPlaceMinorPayloadVersion); 1015 } 1016 1017 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedShellTest) { 1018 DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShell, 1019 false, kInPlaceMinorPayloadVersion); 1020 } 1021 1022 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedShellBadKeyTest) { 1023 DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShellBadKey, 1024 false, kInPlaceMinorPayloadVersion); 1025 } 1026 1027 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedShellRotateCl1Test) { 1028 DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShellRotateCl1, 1029 false, kInPlaceMinorPayloadVersion); 1030 } 1031 1032 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedShellRotateCl2Test) { 1033 DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShellRotateCl2, 1034 false, kInPlaceMinorPayloadVersion); 1035 } 1036 1037 TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSourceOpsTest) { 1038 DoSmallImageTest(false, false, false, -1, kSignatureGenerator, 1039 false, kSourceMinorPayloadVersion); 1040 } 1041 1042 TEST(DeltaPerformerIntegrationTest, RunAsRootMandatoryOperationHashMismatchTest) { 1043 DoOperationHashMismatchTest(kInvalidOperationData, true); 1044 } 1045 1046 } // namespace chromeos_update_engine 1047