xref: /aosp_15_r20/system/update_engine/payload_consumer/delta_performer_integration_test.cc (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
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 <sys/mount.h>
20 
21 #include <algorithm>
22 #include <list>
23 #include <string>
24 #include <vector>
25 
26 #include <base/files/file_path.h>
27 #include <base/files/file_util.h>
28 #include <android-base/stringprintf.h>
29 #include <gmock/gmock-matchers.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/fake_prefs.h"
38 #include "update_engine/common/mock_download_action.h"
39 #include "update_engine/common/mock_prefs.h"
40 #include "update_engine/common/test_utils.h"
41 #include "update_engine/common/testing_constants.h"
42 #include "update_engine/common/utils.h"
43 #include "update_engine/payload_consumer/install_plan.h"
44 #include "update_engine/payload_consumer/payload_constants.h"
45 #include "update_engine/payload_consumer/payload_metadata.h"
46 #include "update_engine/payload_generator/delta_diff_generator.h"
47 #include "update_engine/payload_generator/payload_signer.h"
48 #include "update_engine/update_metadata.pb.h"
49 
50 namespace chromeos_update_engine {
51 
52 using std::list;
53 using std::string;
54 using std::unique_ptr;
55 using std::vector;
56 using test_utils::GetBuildArtifactsPath;
57 using test_utils::kRandomString;
58 using test_utils::ScopedLoopMounter;
59 using test_utils::System;
60 using testing::_;
61 using testing::IsEmpty;
62 using testing::NiceMock;
63 using testing::Not;
64 using testing::Return;
65 
66 static const uint32_t kDefaultKernelSize = 4096;  // Something small for a test
67 // clang-format off
68 static const uint8_t kNewData[] = {'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
69                                    'n', 'e', 'w', ' ', 'd', 'a', 't', 'a', '.'};
70 // clang-format on
71 
72 namespace {
73 struct DeltaState {
74   unique_ptr<ScopedTempFile> a_img;
75   unique_ptr<ScopedTempFile> b_img;
76   unique_ptr<ScopedTempFile> result_img;
77   size_t image_size;
78 
79   unique_ptr<ScopedTempFile> delta_file;
80   // The in-memory copy of delta file.
81   brillo::Blob delta;
82   uint64_t metadata_size;
83   uint32_t metadata_signature_size;
84 
85   unique_ptr<ScopedTempFile> old_kernel;
86   brillo::Blob old_kernel_data;
87 
88   unique_ptr<ScopedTempFile> new_kernel;
89   brillo::Blob new_kernel_data;
90 
91   unique_ptr<ScopedTempFile> result_kernel;
92   brillo::Blob result_kernel_data;
93   size_t kernel_size;
94 
95   // The InstallPlan referenced by the DeltaPerformer. This needs to outlive
96   // the DeltaPerformer.
97   InstallPlan install_plan;
98 
99   // Mock and fake instances used by the delta performer.
100   FakeBootControl fake_boot_control_;
101   FakeHardware fake_hardware_;
102   MockDownloadActionDelegate mock_delegate_;
103 };
104 
105 enum SignatureTest {
106   kSignatureNone,                  // No payload signing.
107   kSignatureGenerator,             // Sign the payload at generation time.
108   kSignatureGenerated,             // Sign the payload after it's generated.
109   kSignatureGeneratedPlaceholder,  // Insert placeholder signatures, then real.
110   kSignatureGeneratedPlaceholderMismatch,  // Insert a wrong sized placeholder.
111   kSignatureGeneratedShell,  // Sign the generated payload through shell cmds.
112   kSignatureGeneratedShellECKey,      // Sign with a EC key through shell cmds.
113   kSignatureGeneratedShellBadKey,     // Sign with a bad key through shell cmds.
114   kSignatureGeneratedShellRotateCl1,  // Rotate key, test client v1
115   kSignatureGeneratedShellRotateCl2,  // Rotate key, test client v2
116 };
117 
118 enum OperationHashTest {
119   kInvalidOperationData,
120   kValidOperationData,
121 };
122 
123 }  // namespace
124 
125 class DeltaPerformerIntegrationTest : public ::testing::Test {
126  public:
RunManifestValidation(const DeltaArchiveManifest & manifest,uint64_t major_version,ErrorCode expected)127   void RunManifestValidation(const DeltaArchiveManifest& manifest,
128                              uint64_t major_version,
129                              ErrorCode expected) {
130     FakePrefs prefs;
131     InstallPlan::Payload payload;
132     InstallPlan install_plan;
133     DeltaPerformer performer{&prefs,
134                              nullptr,
135                              &fake_hardware_,
136                              nullptr,
137                              &install_plan,
138                              &payload,
139                              false /* interactive*/};
140     // Delta performer will treat manifest as kDelta payload
141     // if it's a partial update.
142     payload.type = manifest.partial_update() ? InstallPayloadType::kDelta
143                                              : InstallPayloadType::kFull;
144 
145     // The Manifest we are validating.
146     performer.manifest_.CopyFrom(manifest);
147     performer.major_payload_version_ = major_version;
148 
149     ASSERT_EQ(expected, performer.ValidateManifest());
150   }
AddPartition(DeltaArchiveManifest * manifest,string name,int timestamp)151   void AddPartition(DeltaArchiveManifest* manifest,
152                     string name,
153                     int timestamp) {
154     auto& partition = *manifest->add_partitions();
155     partition.set_version(std::to_string(timestamp));
156     partition.set_partition_name(name);
157   }
158   FakeHardware fake_hardware_;
159 };
160 
CompareFilesByBlock(const string & a_file,const string & b_file,size_t image_size)161 static void CompareFilesByBlock(const string& a_file,
162                                 const string& b_file,
163                                 size_t image_size) {
164   ASSERT_EQ(0U, image_size % kBlockSize);
165 
166   brillo::Blob a_data, b_data;
167   ASSERT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file;
168   ASSERT_TRUE(utils::ReadFile(b_file, &b_data)) << "file failed: " << b_file;
169 
170   EXPECT_GE(a_data.size(), image_size);
171   EXPECT_GE(b_data.size(), image_size);
172   for (size_t i = 0; i < image_size; i += kBlockSize) {
173     ASSERT_EQ(0U, i % kBlockSize);
174     brillo::Blob a_sub(&a_data[i], &a_data[i + kBlockSize]);
175     brillo::Blob b_sub(&b_data[i], &b_data[i + kBlockSize]);
176     ASSERT_EQ(a_sub, b_sub) << "Block " << (i / kBlockSize) << " differs";
177   }
178   if (::testing::Test::HasNonfatalFailure()) {
179     LOG(INFO) << "Compared filesystems with size " << image_size
180               << ", partition A " << a_file << " size: " << a_data.size()
181               << ", partition B " << b_file << " size: " << b_data.size();
182   }
183 }
184 
WriteSparseFile(const string & path,off_t size)185 static bool WriteSparseFile(const string& path, off_t size) {
186   int fd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
187   TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
188   ScopedFdCloser fd_closer(&fd);
189   off_t rc = lseek(fd, size + 1, SEEK_SET);
190   TEST_AND_RETURN_FALSE_ERRNO(rc != static_cast<off_t>(-1));
191   int return_code = ftruncate(fd, size);
192   TEST_AND_RETURN_FALSE_ERRNO(return_code == 0);
193   return true;
194 }
195 
WriteByteAtOffset(const string & path,off_t offset)196 static bool WriteByteAtOffset(const string& path, off_t offset) {
197   int fd = open(path.c_str(), O_CREAT | O_WRONLY, 0644);
198   TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
199   ScopedFdCloser fd_closer(&fd);
200   return utils::PWriteAll(fd, "\0", 1, offset);
201 }
202 
InsertSignaturePlaceholder(size_t signature_size,const string & payload_path,uint64_t * out_metadata_size)203 static bool InsertSignaturePlaceholder(size_t signature_size,
204                                        const string& payload_path,
205                                        uint64_t* out_metadata_size) {
206   vector<brillo::Blob> signatures;
207   signatures.push_back(brillo::Blob(signature_size, 0));
208 
209   return PayloadSigner::AddSignatureToPayload(payload_path,
210                                               {signature_size},
211                                               signatures,
212                                               {},
213                                               payload_path,
214                                               out_metadata_size);
215 }
216 
SignGeneratedPayload(const string & payload_path,uint64_t * out_metadata_size)217 static void SignGeneratedPayload(const string& payload_path,
218                                  uint64_t* out_metadata_size) {
219   string private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
220   size_t signature_size{};
221   ASSERT_TRUE(PayloadSigner::GetMaximumSignatureSize(private_key_path,
222                                                      &signature_size));
223   brillo::Blob metadata_hash, payload_hash;
224   ASSERT_TRUE(PayloadSigner::HashPayloadForSigning(
225       payload_path, {signature_size}, &payload_hash, &metadata_hash));
226   brillo::Blob metadata_signature, payload_signature;
227   ASSERT_TRUE(PayloadSigner::SignHash(
228       payload_hash, private_key_path, &payload_signature));
229   ASSERT_TRUE(PayloadSigner::SignHash(
230       metadata_hash, private_key_path, &metadata_signature));
231   ASSERT_TRUE(PayloadSigner::AddSignatureToPayload(payload_path,
232                                                    {signature_size},
233                                                    {payload_signature},
234                                                    {metadata_signature},
235                                                    payload_path,
236                                                    out_metadata_size));
237   ASSERT_TRUE(PayloadSigner::VerifySignedPayload(
238       payload_path, GetBuildArtifactsPath(kUnittestPublicKeyPath)));
239 }
240 
SignGeneratedShellPayloadWithKeys(const string & payload_path,const vector<string> & private_key_paths,const string & public_key_path,bool verification_success)241 static void SignGeneratedShellPayloadWithKeys(
242     const string& payload_path,
243     const vector<string>& private_key_paths,
244     const string& public_key_path,
245     bool verification_success) {
246   vector<string> signature_size_strings;
247   for (const auto& key_path : private_key_paths) {
248     size_t signature_size{};
249     ASSERT_TRUE(
250         PayloadSigner::GetMaximumSignatureSize(key_path, &signature_size));
251     signature_size_strings.push_back(
252         android::base::StringPrintf("%zu", signature_size));
253   }
254   string signature_size_string =
255       android::base::Join(signature_size_strings, ":");
256 
257   ScopedTempFile hash_file("hash.XXXXXX"), metadata_hash_file("hash.XXXXXX");
258   string delta_generator_path = GetBuildArtifactsPath("delta_generator");
259   ASSERT_EQ(0,
260             System(android::base::StringPrintf(
261                 "%s -in_file=%s -signature_size=%s -out_hash_file=%s "
262                 "-out_metadata_hash_file=%s",
263                 delta_generator_path.c_str(),
264                 payload_path.c_str(),
265                 signature_size_string.c_str(),
266                 hash_file.path().c_str(),
267                 metadata_hash_file.path().c_str())));
268 
269   // Sign the hash with all private keys.
270   list<ScopedTempFile> sig_files, metadata_sig_files;
271   vector<string> sig_file_paths, metadata_sig_file_paths;
272   for (const auto& key_path : private_key_paths) {
273     brillo::Blob hash, signature;
274     ASSERT_TRUE(utils::ReadFile(hash_file.path(), &hash));
275     ASSERT_TRUE(PayloadSigner::SignHash(hash, key_path, &signature));
276 
277     sig_files.emplace_back("signature.XXXXXX");
278     ASSERT_TRUE(
279         test_utils::WriteFileVector(sig_files.back().path(), signature));
280     sig_file_paths.push_back(sig_files.back().path());
281 
282     brillo::Blob metadata_hash, metadata_signature;
283     ASSERT_TRUE(utils::ReadFile(metadata_hash_file.path(), &metadata_hash));
284     ASSERT_TRUE(
285         PayloadSigner::SignHash(metadata_hash, key_path, &metadata_signature));
286 
287     metadata_sig_files.emplace_back("metadata_signature.XXXXXX");
288     ASSERT_TRUE(test_utils::WriteFileVector(metadata_sig_files.back().path(),
289                                             metadata_signature));
290     metadata_sig_file_paths.push_back(metadata_sig_files.back().path());
291   }
292   string sig_files_string = android::base::Join(sig_file_paths, ":");
293   string metadata_sig_files_string =
294       android::base::Join(metadata_sig_file_paths, ":");
295 
296   // Add the signature to the payload.
297   ASSERT_EQ(
298       0,
299       System(android::base::StringPrintf("%s --signature_size=%s -in_file=%s "
300                                          "-payload_signature_file=%s "
301                                          "-metadata_signature_file=%s "
302                                          "-out_file=%s",
303                                          delta_generator_path.c_str(),
304                                          signature_size_string.c_str(),
305                                          payload_path.c_str(),
306                                          sig_files_string.c_str(),
307                                          metadata_sig_files_string.c_str(),
308                                          payload_path.c_str())));
309 
310   int verify_result =
311       System(android::base::StringPrintf("%s -in_file=%s -public_key=%s",
312                                          delta_generator_path.c_str(),
313                                          payload_path.c_str(),
314                                          public_key_path.c_str()));
315 
316   if (verification_success) {
317     ASSERT_EQ(0, verify_result);
318   } else {
319     ASSERT_NE(0, verify_result);
320   }
321 }
322 
SignGeneratedShellPayload(SignatureTest signature_test,const string & payload_path)323 static void SignGeneratedShellPayload(SignatureTest signature_test,
324                                       const string& payload_path) {
325   vector<SignatureTest> supported_test = {
326       kSignatureGeneratedShell,
327       kSignatureGeneratedShellBadKey,
328       kSignatureGeneratedShellECKey,
329       kSignatureGeneratedShellRotateCl1,
330       kSignatureGeneratedShellRotateCl2,
331   };
332   ASSERT_TRUE(std::find(supported_test.begin(),
333                         supported_test.end(),
334                         signature_test) != supported_test.end());
335 
336   string private_key_path;
337   if (signature_test == kSignatureGeneratedShellBadKey) {
338     ASSERT_TRUE(utils::MakeTempFile("key.XXXXXX", &private_key_path, nullptr));
339   } else if (signature_test == kSignatureGeneratedShellECKey) {
340     private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyECPath);
341   } else {
342     private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
343   }
344   ScopedPathUnlinker key_unlinker(private_key_path);
345   key_unlinker.set_should_remove(signature_test ==
346                                  kSignatureGeneratedShellBadKey);
347 
348   // Generates a new private key that will not match the public key.
349   if (signature_test == kSignatureGeneratedShellBadKey) {
350     LOG(INFO) << "Generating a mismatched private key.";
351     // The code below executes the equivalent of:
352     // openssl genrsa -out <private_key_path> 2048
353     RSA* rsa = RSA_new();
354     BIGNUM* e = BN_new();
355     ASSERT_EQ(1, BN_set_word(e, RSA_F4));
356     ASSERT_EQ(1, RSA_generate_key_ex(rsa, 2048, e, nullptr));
357     BN_free(e);
358     FILE* fprikey = fopen(private_key_path.c_str(), "w");
359     EXPECT_NE(nullptr, fprikey);
360     ASSERT_EQ(1,
361               PEM_write_RSAPrivateKey(
362                   fprikey, rsa, nullptr, nullptr, 0, nullptr, nullptr));
363     fclose(fprikey);
364     RSA_free(rsa);
365   }
366 
367   vector<string> private_key_paths = {private_key_path};
368   if (signature_test == kSignatureGeneratedShellRotateCl1 ||
369       signature_test == kSignatureGeneratedShellRotateCl2) {
370     private_key_paths.push_back(
371         GetBuildArtifactsPath(kUnittestPrivateKey2Path));
372   }
373 
374   string public_key;
375   if (signature_test == kSignatureGeneratedShellRotateCl2) {
376     public_key = GetBuildArtifactsPath(kUnittestPublicKey2Path);
377   } else if (signature_test == kSignatureGeneratedShellECKey) {
378     public_key = GetBuildArtifactsPath(kUnittestPublicKeyECPath);
379   } else {
380     public_key = GetBuildArtifactsPath(kUnittestPublicKeyPath);
381   }
382 
383   bool verification_success = signature_test != kSignatureGeneratedShellBadKey;
384   SignGeneratedShellPayloadWithKeys(
385       payload_path, private_key_paths, public_key, verification_success);
386 }
387 
GenerateDeltaFile(bool full_kernel,bool full_rootfs,ssize_t chunk_size,SignatureTest signature_test,DeltaState * state,uint32_t minor_version)388 static void GenerateDeltaFile(bool full_kernel,
389                               bool full_rootfs,
390                               ssize_t chunk_size,
391                               SignatureTest signature_test,
392                               DeltaState* state,
393                               uint32_t minor_version) {
394   state->a_img.reset(new ScopedTempFile("a_img.XXXXXX"));
395   state->b_img.reset(new ScopedTempFile("b_img.XXXXXX"));
396 
397   // result_img is used in minor version 2. Instead of applying the update
398   // in-place on A, we apply it to a new image, result_img.
399   state->result_img.reset(new ScopedTempFile("result_img.XXXXXX"));
400 
401   ASSERT_TRUE(
402       base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
403                      base::FilePath(state->a_img->path())));
404 
405   state->image_size = utils::FileSize(state->a_img->path());
406 
407   // Make some changes to the A image.
408   {
409     string a_mnt;
410     ScopedLoopMounter b_mounter(state->a_img->path(), &a_mnt, 0);
411 
412     brillo::Blob hardtocompress;
413     while (hardtocompress.size() < 3 * kBlockSize) {
414       hardtocompress.insert(hardtocompress.end(),
415                             std::begin(kRandomString),
416                             std::end(kRandomString));
417     }
418     ASSERT_TRUE(utils::WriteFile(
419         android::base::StringPrintf("%s/hardtocompress", a_mnt.c_str()).c_str(),
420         hardtocompress.data(),
421         hardtocompress.size()));
422 
423     brillo::Blob zeros(16 * 1024, 0);
424     ASSERT_EQ(static_cast<int>(zeros.size()),
425               base::WriteFile(base::FilePath(android::base::StringPrintf(
426                                   "%s/move-to-sparse", a_mnt.c_str())),
427                               reinterpret_cast<const char*>(zeros.data()),
428                               zeros.size()));
429 
430     ASSERT_TRUE(WriteSparseFile(
431         android::base::StringPrintf("%s/move-from-sparse", a_mnt.c_str()),
432         16 * 1024));
433 
434     ASSERT_TRUE(WriteByteAtOffset(
435         android::base::StringPrintf("%s/move-semi-sparse", a_mnt.c_str()),
436         4096));
437 
438     // Write 1 MiB of 0xff to try to catch the case where writing a bsdiff
439     // patch fails to zero out the final block.
440     brillo::Blob ones(1024 * 1024, 0xff);
441     ASSERT_TRUE(utils::WriteFile(
442         android::base::StringPrintf("%s/ones", a_mnt.c_str()).c_str(),
443         ones.data(),
444         ones.size()));
445   }
446 
447   // Create a result image with image_size bytes of garbage.
448   brillo::Blob ones(state->image_size, 0xff);
449   ASSERT_TRUE(utils::WriteFile(
450       state->result_img->path().c_str(), ones.data(), ones.size()));
451   ASSERT_EQ(utils::FileSize(state->a_img->path()),
452             utils::FileSize(state->result_img->path()));
453 
454   ASSERT_TRUE(
455       base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
456                      base::FilePath(state->b_img->path())));
457   {
458     // Make some changes to the B image.
459     string b_mnt;
460     ScopedLoopMounter b_mounter(state->b_img->path(), &b_mnt, 0);
461     base::FilePath mnt_path(b_mnt);
462 
463     ASSERT_TRUE(base::CopyFile(mnt_path.Append("regular-small"),
464                                mnt_path.Append("regular-small2")));
465 #if BASE_VER < 800000
466     ASSERT_TRUE(base::DeleteFile(mnt_path.Append("regular-small"), false));
467 #else
468     ASSERT_TRUE(base::DeleteFile(mnt_path.Append("regular-small")));
469 #endif
470     ASSERT_TRUE(base::Move(mnt_path.Append("regular-small2"),
471                            mnt_path.Append("regular-small")));
472     ASSERT_TRUE(
473         test_utils::WriteFileString(mnt_path.Append("foo").value(), "foo"));
474     ASSERT_EQ(0, base::WriteFile(mnt_path.Append("emptyfile"), "", 0));
475 
476     ASSERT_TRUE(
477         WriteSparseFile(mnt_path.Append("fullsparse").value(), 1024 * 1024));
478     ASSERT_TRUE(
479         WriteSparseFile(mnt_path.Append("move-to-sparse").value(), 16 * 1024));
480 
481     brillo::Blob zeros(16 * 1024, 0);
482     ASSERT_EQ(static_cast<int>(zeros.size()),
483               base::WriteFile(mnt_path.Append("move-from-sparse"),
484                               reinterpret_cast<const char*>(zeros.data()),
485                               zeros.size()));
486 
487     ASSERT_TRUE(
488         WriteByteAtOffset(mnt_path.Append("move-semi-sparse").value(), 4096));
489     ASSERT_TRUE(WriteByteAtOffset(mnt_path.Append("partsparse").value(), 4096));
490 
491     ASSERT_TRUE(
492         base::CopyFile(mnt_path.Append("regular-16k"), mnt_path.Append("tmp")));
493     ASSERT_TRUE(base::Move(mnt_path.Append("tmp"),
494                            mnt_path.Append("link-hard-regular-16k")));
495 
496 #if BASE_VER < 800000
497     ASSERT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink"), false));
498 #else
499     ASSERT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink")));
500 #endif
501     ASSERT_TRUE(test_utils::WriteFileString(
502         mnt_path.Append("link-short_symlink").value(), "foobar"));
503 
504     brillo::Blob hardtocompress;
505     while (hardtocompress.size() < 3 * kBlockSize) {
506       hardtocompress.insert(hardtocompress.end(),
507                             std::begin(kRandomString),
508                             std::end(kRandomString));
509     }
510     ASSERT_TRUE(utils::WriteFile(
511         android::base::StringPrintf("%s/hardtocompress", b_mnt.c_str()).c_str(),
512         hardtocompress.data(),
513         hardtocompress.size()));
514   }
515 
516   state->old_kernel.reset(new ScopedTempFile("old_kernel.XXXXXX"));
517   state->new_kernel.reset(new ScopedTempFile("new_kernel.XXXXXX"));
518   state->result_kernel.reset(new ScopedTempFile("result_kernel.XXXXXX"));
519   state->kernel_size = kDefaultKernelSize;
520   state->old_kernel_data.resize(kDefaultKernelSize);
521   state->new_kernel_data.resize(state->old_kernel_data.size());
522   state->result_kernel_data.resize(state->old_kernel_data.size());
523   test_utils::FillWithData(&state->old_kernel_data);
524   test_utils::FillWithData(&state->new_kernel_data);
525   test_utils::FillWithData(&state->result_kernel_data);
526 
527   // change the new kernel data
528   std::copy(
529       std::begin(kNewData), std::end(kNewData), state->new_kernel_data.begin());
530 
531   // Write kernels to disk
532   ASSERT_TRUE(utils::WriteFile(state->old_kernel->path().c_str(),
533                                state->old_kernel_data.data(),
534                                state->old_kernel_data.size()));
535   ASSERT_TRUE(utils::WriteFile(state->new_kernel->path().c_str(),
536                                state->new_kernel_data.data(),
537                                state->new_kernel_data.size()));
538   ASSERT_TRUE(utils::WriteFile(state->result_kernel->path().c_str(),
539                                state->result_kernel_data.data(),
540                                state->result_kernel_data.size()));
541 
542   state->delta_file.reset(new ScopedTempFile("delta.XXXXXX"));
543   {
544     const string private_key =
545         signature_test == kSignatureGenerator
546             ? GetBuildArtifactsPath(kUnittestPrivateKeyPath)
547             : "";
548 
549     PayloadGenerationConfig payload_config;
550     payload_config.is_delta = !full_rootfs;
551     payload_config.hard_chunk_size = chunk_size;
552     payload_config.rootfs_partition_size = kRootFSPartitionSize;
553     payload_config.version.major = kBrilloMajorPayloadVersion;
554     payload_config.version.minor = minor_version;
555     if (!full_rootfs) {
556       payload_config.source.partitions.emplace_back(kPartitionNameRoot);
557       payload_config.source.partitions.emplace_back(kPartitionNameKernel);
558       payload_config.source.partitions.front().path = state->a_img->path();
559       if (!full_kernel)
560         payload_config.source.partitions.back().path =
561             state->old_kernel->path();
562       ASSERT_TRUE(payload_config.source.LoadImageSize());
563       for (PartitionConfig& part : payload_config.source.partitions)
564         ASSERT_TRUE(part.OpenFilesystem());
565     } else {
566       if (payload_config.hard_chunk_size == -1)
567         // Use 1 MiB chunk size for the full unittests.
568         payload_config.hard_chunk_size = 1024 * 1024;
569     }
570     payload_config.target.partitions.emplace_back(kPartitionNameRoot);
571     payload_config.target.partitions.back().path = state->b_img->path();
572     payload_config.target.partitions.emplace_back(kPartitionNameKernel);
573     payload_config.target.partitions.back().path = state->new_kernel->path();
574     ASSERT_TRUE(payload_config.target.LoadImageSize());
575     for (PartitionConfig& part : payload_config.target.partitions)
576       ASSERT_TRUE(part.OpenFilesystem());
577 
578     ASSERT_TRUE(payload_config.Validate());
579     ASSERT_TRUE(GenerateUpdatePayloadFile(payload_config,
580                                           state->delta_file->path(),
581                                           private_key,
582                                           &state->metadata_size));
583   }
584   // Extend the "partitions" holding the file system a bit.
585   ASSERT_EQ(0,
586             HANDLE_EINTR(truncate(state->a_img->path().c_str(),
587                                   state->image_size + 1024 * 1024)));
588   ASSERT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
589             utils::FileSize(state->a_img->path()));
590   ASSERT_EQ(0,
591             HANDLE_EINTR(truncate(state->b_img->path().c_str(),
592                                   state->image_size + 1024 * 1024)));
593   ASSERT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
594             utils::FileSize(state->b_img->path()));
595 
596   if (signature_test == kSignatureGeneratedPlaceholder ||
597       signature_test == kSignatureGeneratedPlaceholderMismatch) {
598     size_t signature_size{};
599     ASSERT_TRUE(PayloadSigner::GetMaximumSignatureSize(
600         GetBuildArtifactsPath(kUnittestPrivateKeyPath), &signature_size));
601     LOG(INFO) << "Inserting placeholder signature.";
602     ASSERT_TRUE(InsertSignaturePlaceholder(
603         signature_size, state->delta_file->path(), &state->metadata_size));
604 
605     if (signature_test == kSignatureGeneratedPlaceholderMismatch) {
606       signature_size -= 1;
607       LOG(INFO) << "Inserting mismatched placeholder signature.";
608       ASSERT_TRUE(InsertSignaturePlaceholder(
609           signature_size, state->delta_file->path(), &state->metadata_size));
610       return;
611     }
612   }
613 
614   if (signature_test == kSignatureGenerated ||
615       signature_test == kSignatureGeneratedPlaceholder ||
616       signature_test == kSignatureGeneratedPlaceholderMismatch) {
617     // Generate the signed payload and update the metadata size in state to
618     // reflect the new size after adding the signature operation to the
619     // manifest.
620     LOG(INFO) << "Signing payload.";
621     SignGeneratedPayload(state->delta_file->path(), &state->metadata_size);
622   } else if (signature_test == kSignatureGeneratedShell ||
623              signature_test == kSignatureGeneratedShellECKey ||
624              signature_test == kSignatureGeneratedShellBadKey ||
625              signature_test == kSignatureGeneratedShellRotateCl1 ||
626              signature_test == kSignatureGeneratedShellRotateCl2) {
627     SignGeneratedShellPayload(signature_test, state->delta_file->path());
628   }
629 }
630 
ApplyDeltaFile(bool full_kernel,bool full_rootfs,SignatureTest signature_test,DeltaState * state,bool hash_checks_mandatory,OperationHashTest op_hash_test,DeltaPerformer ** performer,uint32_t minor_version)631 static void ApplyDeltaFile(bool full_kernel,
632                            bool full_rootfs,
633                            SignatureTest signature_test,
634                            DeltaState* state,
635                            bool hash_checks_mandatory,
636                            OperationHashTest op_hash_test,
637                            DeltaPerformer** performer,
638                            uint32_t minor_version) {
639   // Check the metadata.
640   {
641     ASSERT_TRUE(utils::ReadFile(state->delta_file->path(), &state->delta));
642     PayloadMetadata payload_metadata;
643     ASSERT_TRUE(payload_metadata.ParsePayloadHeader(state->delta));
644     state->metadata_size = payload_metadata.GetMetadataSize();
645     LOG(INFO) << "Metadata size: " << state->metadata_size;
646     LOG(INFO) << "Payload size: " << state->delta.size();
647     state->metadata_signature_size =
648         payload_metadata.GetMetadataSignatureSize();
649     LOG(INFO) << "Metadata signature size: " << state->metadata_signature_size;
650 
651     DeltaArchiveManifest manifest;
652     ASSERT_TRUE(payload_metadata.GetManifest(state->delta, &manifest));
653     if (signature_test == kSignatureNone) {
654       ASSERT_FALSE(manifest.has_signatures_offset());
655       ASSERT_FALSE(manifest.has_signatures_size());
656     } else {
657       ASSERT_TRUE(manifest.has_signatures_offset());
658       ASSERT_TRUE(manifest.has_signatures_size());
659       Signatures sigs_message;
660       ASSERT_TRUE(sigs_message.ParseFromArray(
661           &state->delta[state->metadata_size + state->metadata_signature_size +
662                         manifest.signatures_offset()],
663           manifest.signatures_size()));
664       if (signature_test == kSignatureGeneratedShellRotateCl1 ||
665           signature_test == kSignatureGeneratedShellRotateCl2)
666         ASSERT_EQ(2, sigs_message.signatures_size());
667       else
668         ASSERT_EQ(1, sigs_message.signatures_size());
669       const Signatures::Signature& signature = sigs_message.signatures(0);
670 
671       vector<string> key_paths{GetBuildArtifactsPath(kUnittestPrivateKeyPath)};
672       if (signature_test == kSignatureGeneratedShellECKey) {
673         key_paths = {GetBuildArtifactsPath(kUnittestPrivateKeyECPath)};
674       } else if (signature_test == kSignatureGeneratedShellRotateCl1 ||
675                  signature_test == kSignatureGeneratedShellRotateCl2) {
676         key_paths.push_back(GetBuildArtifactsPath(kUnittestPrivateKey2Path));
677       }
678       uint64_t expected_sig_data_length = 0;
679       ASSERT_TRUE(PayloadSigner::SignatureBlobLength(
680           key_paths, &expected_sig_data_length));
681       ASSERT_EQ(expected_sig_data_length, manifest.signatures_size());
682       ASSERT_FALSE(signature.data().empty());
683     }
684 
685     // TODO(ahassani): Make |DeltaState| into a partition list kind of struct
686     // instead of hardcoded kernel/rootfs so its cleaner and we can make the
687     // following code into a helper function instead.
688     const auto& kernel_part = *std::find_if(
689         manifest.partitions().begin(),
690         manifest.partitions().end(),
691         [](const PartitionUpdate& partition) {
692           return partition.partition_name() == kPartitionNameKernel;
693         });
694     if (full_kernel) {
695       ASSERT_FALSE(kernel_part.has_old_partition_info());
696     } else {
697       ASSERT_EQ(state->old_kernel_data.size(),
698                 kernel_part.old_partition_info().size());
699       ASSERT_FALSE(kernel_part.old_partition_info().hash().empty());
700     }
701     ASSERT_EQ(state->new_kernel_data.size(),
702               kernel_part.new_partition_info().size());
703     ASSERT_FALSE(kernel_part.new_partition_info().hash().empty());
704 
705     const auto& rootfs_part =
706         *std::find_if(manifest.partitions().begin(),
707                       manifest.partitions().end(),
708                       [](const PartitionUpdate& partition) {
709                         return partition.partition_name() == kPartitionNameRoot;
710                       });
711     if (full_rootfs) {
712       ASSERT_FALSE(rootfs_part.has_old_partition_info());
713     } else {
714       ASSERT_FALSE(rootfs_part.old_partition_info().hash().empty());
715     }
716     ASSERT_FALSE(rootfs_part.new_partition_info().hash().empty());
717   }
718 
719   NiceMock<MockPrefs> prefs;
720   ON_CALL(prefs, SetInt64(kPrefsManifestMetadataSize, -1))
721       .WillByDefault(Return(true));
722   ON_CALL(prefs, SetInt64(kPrefsUpdateCheckResponseHash, -1))
723       .WillByDefault(Return(true));
724   ON_CALL(prefs, GetString(kPrefsUpdateCheckResponseHash, _))
725       .WillByDefault(Return(true));
726   ON_CALL(prefs, GetString(kPrefsDynamicPartitionMetadataUpdated, _))
727       .WillByDefault(Return(true));
728 
729   // Set default expectation to ignore uninteresting calls to
730   // SetString/SetInt64. When starting an update delta_performer might reset
731   // update checkpoints, which results in a lot of calls with empty string or
732   // integer -1. Ignore these.
733   EXPECT_CALL(prefs, SetString(_, IsEmpty())).WillRepeatedly(Return(true));
734   EXPECT_CALL(prefs, SetInt64(_, -1)).WillRepeatedly(Return(true));
735   EXPECT_CALL(prefs, SetInt64(_, 0)).WillRepeatedly(Return(true));
736 
737   EXPECT_CALL(prefs, SetInt64(kPrefsManifestMetadataSize, state->metadata_size))
738       .WillOnce(Return(true));
739   EXPECT_CALL(
740       prefs,
741       SetInt64(kPrefsManifestSignatureSize, state->metadata_signature_size))
742       .WillOnce(Return(true));
743   EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextOperation, _))
744       .WillRepeatedly(Return(true));
745   EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextOperation, _))
746       .WillOnce(Return(false));
747   EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataOffset, _))
748       .WillRepeatedly(Return(true));
749   EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataLength, _))
750       .WillRepeatedly(Return(true));
751   EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSHA256Context, _))
752       .WillRepeatedly(Return(true));
753   EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignedSHA256Context, _))
754       .WillRepeatedly(Return(true));
755   EXPECT_CALL(prefs, SetString(kPrefsDynamicPartitionMetadataUpdated, _))
756       .WillRepeatedly(Return(true));
757   EXPECT_CALL(prefs,
758               SetString(kPrefsManifestBytes,
759                         testing::SizeIs(state->metadata_signature_size +
760                                         state->metadata_size)))
761       .WillRepeatedly(Return(true));
762   if (op_hash_test == kValidOperationData && signature_test != kSignatureNone) {
763     EXPECT_CALL(prefs,
764                 SetString(kPrefsUpdateStateSignatureBlob, Not(IsEmpty())))
765         .WillRepeatedly(Return(true));
766   }
767 
768   EXPECT_CALL(state->mock_delegate_, ShouldCancel(_))
769       .WillRepeatedly(Return(false));
770 
771   // Update the A image in place.
772   InstallPlan* install_plan = &state->install_plan;
773   install_plan->hash_checks_mandatory = hash_checks_mandatory;
774   install_plan->payloads = {{.size = state->delta.size(),
775                              .metadata_size = state->metadata_size,
776                              .type = (full_kernel && full_rootfs)
777                                          ? InstallPayloadType::kFull
778                                          : InstallPayloadType::kDelta}};
779   install_plan->source_slot = 0;
780   install_plan->target_slot = 1;
781 
782   InstallPlan::Partition root_part;
783   root_part.name = kPartitionNameRoot;
784 
785   InstallPlan::Partition kernel_part;
786   kernel_part.name = kPartitionNameKernel;
787 
788   LOG(INFO) << "Setting payload metadata size in Omaha  = "
789             << state->metadata_size;
790   ASSERT_TRUE(PayloadSigner::GetMetadataSignature(
791       state->delta.data(),
792       state->metadata_size,
793       (signature_test == kSignatureGeneratedShellECKey)
794           ? GetBuildArtifactsPath(kUnittestPrivateKeyECPath)
795           : GetBuildArtifactsPath(kUnittestPrivateKeyPath),
796       &install_plan->payloads[0].metadata_signature));
797   ASSERT_FALSE(install_plan->payloads[0].metadata_signature.empty());
798 
799   *performer = new DeltaPerformer(&prefs,
800                                   &state->fake_boot_control_,
801                                   &state->fake_hardware_,
802                                   &state->mock_delegate_,
803                                   install_plan,
804                                   &install_plan->payloads[0],
805                                   false /* interactive */,
806                                   "");
807   string public_key_path = signature_test == kSignatureGeneratedShellECKey
808                                ? GetBuildArtifactsPath(kUnittestPublicKeyECPath)
809                                : GetBuildArtifactsPath(kUnittestPublicKeyPath);
810   ASSERT_TRUE(utils::FileExists(public_key_path.c_str()));
811   (*performer)->set_public_key_path(public_key_path);
812 
813   ASSERT_EQ(
814       static_cast<off_t>(state->image_size),
815       HashCalculator::RawHashOfFile(
816           state->a_img->path(), state->image_size, &root_part.source_hash));
817   ASSERT_TRUE(HashCalculator::RawHashOfData(state->old_kernel_data,
818                                             &kernel_part.source_hash));
819 
820   // The partitions should be empty before DeltaPerformer.
821   install_plan->partitions.clear();
822 
823   state->fake_boot_control_.SetPartitionDevice(
824       kPartitionNameRoot, install_plan->source_slot, state->a_img->path());
825   state->fake_boot_control_.SetPartitionDevice(kPartitionNameKernel,
826                                                install_plan->source_slot,
827                                                state->old_kernel->path());
828   state->fake_boot_control_.SetPartitionDevice(
829       kPartitionNameRoot, install_plan->target_slot, state->result_img->path());
830   state->fake_boot_control_.SetPartitionDevice(kPartitionNameKernel,
831                                                install_plan->target_slot,
832                                                state->result_kernel->path());
833 
834   ErrorCode expected_error{}, actual_error{};
835   bool continue_writing{};
836   switch (op_hash_test) {
837     case kInvalidOperationData: {
838       // Muck with some random offset post the metadata size so that
839       // some operation hash will result in a mismatch.
840       int some_offset = state->metadata_size + 300;
841       LOG(INFO) << "Tampered value at offset: " << some_offset;
842       state->delta[some_offset]++;
843       expected_error = ErrorCode::kDownloadOperationHashMismatch;
844       continue_writing = false;
845       break;
846     }
847 
848     case kValidOperationData:
849     default:
850       // no change.
851       expected_error = ErrorCode::kSuccess;
852       continue_writing = true;
853       break;
854   }
855 
856   // Write at some number of bytes per operation. Arbitrarily chose 5.
857   const size_t kBytesPerWrite = 5;
858   for (size_t i = 0; i < state->delta.size(); i += kBytesPerWrite) {
859     size_t count = std::min(state->delta.size() - i, kBytesPerWrite);
860     bool write_succeeded =
861         ((*performer)->Write(&state->delta[i], count, &actual_error));
862     // Normally write_succeeded should be true every time and
863     // actual_error should be ErrorCode::kSuccess. If so, continue the loop.
864     // But if we seeded an operation hash error above, then write_succeeded
865     // will be false. The failure may happen at any operation n. So, all
866     // Writes until n-1 should succeed and the nth operation will fail with
867     // actual_error. In this case, we should bail out of the loop because
868     // we cannot proceed applying the delta.
869     if (!write_succeeded) {
870       LOG(INFO) << "Write failed. Checking if it failed with expected error";
871       ASSERT_EQ(expected_error, actual_error);
872       if (!continue_writing) {
873         LOG(INFO) << "Cannot continue writing. Bailing out.";
874         break;
875       }
876     }
877 
878     ASSERT_EQ(ErrorCode::kSuccess, actual_error);
879   }
880 
881   // If we had continued all the way through, Close should succeed.
882   // Otherwise, it should fail. Check appropriately.
883   bool close_result = (*performer)->Close();
884   if (continue_writing)
885     ASSERT_EQ(0, close_result);
886   else
887     ASSERT_LE(0, close_result);
888 }
889 
VerifyPayloadResult(DeltaPerformer * performer,DeltaState * state,ErrorCode expected_result,uint32_t minor_version)890 void VerifyPayloadResult(DeltaPerformer* performer,
891                          DeltaState* state,
892                          ErrorCode expected_result,
893                          uint32_t minor_version) {
894   if (!performer) {
895     ASSERT_TRUE(!"Skipping payload verification since performer is null.");
896     return;
897   }
898 
899   LOG(INFO) << "Verifying payload for expected result " << expected_result;
900   brillo::Blob expected_hash;
901   HashCalculator::RawHashOfData(state->delta, &expected_hash);
902   ASSERT_EQ(expected_result,
903             performer->VerifyPayload(expected_hash, state->delta.size()));
904   LOG(INFO) << "Verified payload.";
905 
906   if (expected_result != ErrorCode::kSuccess) {
907     // no need to verify new partition if VerifyPayload failed.
908     return;
909   }
910   ASSERT_NO_FATAL_FAILURE(CompareFilesByBlock(state->result_kernel->path(),
911                                               state->new_kernel->path(),
912                                               state->kernel_size));
913   ASSERT_NO_FATAL_FAILURE(CompareFilesByBlock(
914       state->result_img->path(), state->b_img->path(), state->image_size));
915 
916   brillo::Blob updated_kernel_partition;
917   ASSERT_TRUE(
918       utils::ReadFile(state->result_kernel->path(), &updated_kernel_partition));
919   ASSERT_GE(updated_kernel_partition.size(), std::size(kNewData));
920   ASSERT_TRUE(std::equal(std::begin(kNewData),
921                          std::end(kNewData),
922                          updated_kernel_partition.begin()));
923 
924   const auto& partitions = state->install_plan.partitions;
925   ASSERT_EQ(2U, partitions.size());
926   ASSERT_EQ(kPartitionNameRoot, partitions[0].name);
927   ASSERT_EQ(kPartitionNameKernel, partitions[1].name);
928 
929   ASSERT_EQ(kDefaultKernelSize, partitions[1].target_size);
930   brillo::Blob expected_new_kernel_hash;
931   ASSERT_TRUE(HashCalculator::RawHashOfData(state->new_kernel_data,
932                                             &expected_new_kernel_hash));
933   ASSERT_EQ(expected_new_kernel_hash, partitions[1].target_hash);
934 
935   ASSERT_EQ(state->image_size, partitions[0].target_size);
936   brillo::Blob expected_new_rootfs_hash;
937   ASSERT_EQ(
938       static_cast<off_t>(state->image_size),
939       HashCalculator::RawHashOfFile(
940           state->b_img->path(), state->image_size, &expected_new_rootfs_hash));
941   ASSERT_EQ(expected_new_rootfs_hash, partitions[0].target_hash);
942 }
943 
VerifyPayload(DeltaPerformer * performer,DeltaState * state,SignatureTest signature_test,uint32_t minor_version)944 void VerifyPayload(DeltaPerformer* performer,
945                    DeltaState* state,
946                    SignatureTest signature_test,
947                    uint32_t minor_version) {
948   ErrorCode expected_result = ErrorCode::kSuccess;
949   switch (signature_test) {
950     case kSignatureNone:
951       expected_result = ErrorCode::kSignedDeltaPayloadExpectedError;
952       break;
953     case kSignatureGeneratedShellBadKey:
954       expected_result = ErrorCode::kDownloadPayloadPubKeyVerificationError;
955       break;
956     default:
957       break;  // appease gcc
958   }
959 
960   ASSERT_NO_FATAL_FAILURE(
961       VerifyPayloadResult(performer, state, expected_result, minor_version));
962 }
963 
DoSmallImageTest(bool full_kernel,bool full_rootfs,ssize_t chunk_size,SignatureTest signature_test,bool hash_checks_mandatory,uint32_t minor_version)964 void DoSmallImageTest(bool full_kernel,
965                       bool full_rootfs,
966                       ssize_t chunk_size,
967                       SignatureTest signature_test,
968                       bool hash_checks_mandatory,
969                       uint32_t minor_version) {
970   DeltaState state;
971   DeltaPerformer* performer = nullptr;
972   ASSERT_NO_FATAL_FAILURE(GenerateDeltaFile(full_kernel,
973                                             full_rootfs,
974                                             chunk_size,
975                                             signature_test,
976                                             &state,
977                                             minor_version));
978 
979   ASSERT_NO_FATAL_FAILURE(ApplyDeltaFile(full_kernel,
980                                          full_rootfs,
981                                          signature_test,
982                                          &state,
983                                          hash_checks_mandatory,
984                                          kValidOperationData,
985                                          &performer,
986                                          minor_version));
987   ASSERT_NO_FATAL_FAILURE(
988       VerifyPayload(performer, &state, signature_test, minor_version));
989   delete performer;
990 }
991 
DoOperationHashMismatchTest(OperationHashTest op_hash_test,bool hash_checks_mandatory)992 void DoOperationHashMismatchTest(OperationHashTest op_hash_test,
993                                  bool hash_checks_mandatory) {
994   DeltaState state;
995   uint64_t minor_version = kFullPayloadMinorVersion;
996   GenerateDeltaFile(true, true, -1, kSignatureGenerated, &state, minor_version);
997   DeltaPerformer* performer = nullptr;
998   ASSERT_NO_FATAL_FAILURE(ApplyDeltaFile(true,
999                                          true,
1000                                          kSignatureGenerated,
1001                                          &state,
1002                                          hash_checks_mandatory,
1003                                          op_hash_test,
1004                                          &performer,
1005                                          minor_version));
1006   delete performer;
1007 }
1008 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageTest)1009 TEST_F(DeltaPerformerIntegrationTest, RunAsRootSmallImageTest) {
1010   DoSmallImageTest(
1011       false, false, -1, kSignatureGenerator, false, kSourceMinorPayloadVersion);
1012 }
1013 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignaturePlaceholderTest)1014 TEST_F(DeltaPerformerIntegrationTest,
1015        RunAsRootSmallImageSignaturePlaceholderTest) {
1016   DoSmallImageTest(false,
1017                    false,
1018                    -1,
1019                    kSignatureGeneratedPlaceholder,
1020                    false,
1021                    kSourceMinorPayloadVersion);
1022 }
1023 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignaturePlaceholderMismatchTest)1024 TEST_F(DeltaPerformerIntegrationTest,
1025        RunAsRootSmallImageSignaturePlaceholderMismatchTest) {
1026   DeltaState state;
1027   GenerateDeltaFile(false,
1028                     false,
1029                     -1,
1030                     kSignatureGeneratedPlaceholderMismatch,
1031                     &state,
1032                     kSourceMinorPayloadVersion);
1033 }
1034 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageChunksTest)1035 TEST_F(DeltaPerformerIntegrationTest, RunAsRootSmallImageChunksTest) {
1036   DoSmallImageTest(false,
1037                    false,
1038                    kBlockSize,
1039                    kSignatureGenerator,
1040                    false,
1041                    kSourceMinorPayloadVersion);
1042 }
1043 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootFullKernelSmallImageTest)1044 TEST_F(DeltaPerformerIntegrationTest, RunAsRootFullKernelSmallImageTest) {
1045   DoSmallImageTest(
1046       true, false, -1, kSignatureGenerator, false, kSourceMinorPayloadVersion);
1047 }
1048 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootFullSmallImageTest)1049 TEST_F(DeltaPerformerIntegrationTest, RunAsRootFullSmallImageTest) {
1050   DoSmallImageTest(
1051       true, true, -1, kSignatureGenerator, true, kFullPayloadMinorVersion);
1052 }
1053 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignNoneTest)1054 TEST_F(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignNoneTest) {
1055   DoSmallImageTest(
1056       false, false, -1, kSignatureNone, false, kSourceMinorPayloadVersion);
1057 }
1058 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedTest)1059 TEST_F(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedTest) {
1060   DoSmallImageTest(
1061       false, false, -1, kSignatureGenerated, true, kSourceMinorPayloadVersion);
1062 }
1063 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedShellTest)1064 TEST_F(DeltaPerformerIntegrationTest,
1065        RunAsRootSmallImageSignGeneratedShellTest) {
1066   DoSmallImageTest(false,
1067                    false,
1068                    -1,
1069                    kSignatureGeneratedShell,
1070                    false,
1071                    kSourceMinorPayloadVersion);
1072 }
1073 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedShellECKeyTest)1074 TEST_F(DeltaPerformerIntegrationTest,
1075        RunAsRootSmallImageSignGeneratedShellECKeyTest) {
1076   DoSmallImageTest(false,
1077                    false,
1078                    -1,
1079                    kSignatureGeneratedShellECKey,
1080                    false,
1081                    kSourceMinorPayloadVersion);
1082 }
1083 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedShellBadKeyTest)1084 TEST_F(DeltaPerformerIntegrationTest,
1085        RunAsRootSmallImageSignGeneratedShellBadKeyTest) {
1086   DoSmallImageTest(false,
1087                    false,
1088                    -1,
1089                    kSignatureGeneratedShellBadKey,
1090                    false,
1091                    kSourceMinorPayloadVersion);
1092 }
1093 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedShellRotateCl1Test)1094 TEST_F(DeltaPerformerIntegrationTest,
1095        RunAsRootSmallImageSignGeneratedShellRotateCl1Test) {
1096   DoSmallImageTest(false,
1097                    false,
1098                    -1,
1099                    kSignatureGeneratedShellRotateCl1,
1100                    false,
1101                    kSourceMinorPayloadVersion);
1102 }
1103 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedShellRotateCl2Test)1104 TEST_F(DeltaPerformerIntegrationTest,
1105        RunAsRootSmallImageSignGeneratedShellRotateCl2Test) {
1106   DoSmallImageTest(false,
1107                    false,
1108                    -1,
1109                    kSignatureGeneratedShellRotateCl2,
1110                    false,
1111                    kSourceMinorPayloadVersion);
1112 }
1113 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSourceOpsTest)1114 TEST_F(DeltaPerformerIntegrationTest, RunAsRootSmallImageSourceOpsTest) {
1115   DoSmallImageTest(
1116       false, false, -1, kSignatureGenerator, false, kSourceMinorPayloadVersion);
1117 }
1118 
TEST_F(DeltaPerformerIntegrationTest,RunAsRootMandatoryOperationHashMismatchTest)1119 TEST_F(DeltaPerformerIntegrationTest,
1120        RunAsRootMandatoryOperationHashMismatchTest) {
1121   DoOperationHashMismatchTest(kInvalidOperationData, true);
1122 }
1123 
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampSuccess)1124 TEST_F(DeltaPerformerIntegrationTest, ValidatePerPartitionTimestampSuccess) {
1125   // The Manifest we are validating.
1126   DeltaArchiveManifest manifest;
1127 
1128   fake_hardware_.SetVersion("system", "5");
1129   fake_hardware_.SetVersion("product", "99");
1130   fake_hardware_.SetBuildTimestamp(1);
1131 
1132   manifest.set_minor_version(kFullPayloadMinorVersion);
1133   manifest.set_max_timestamp(2);
1134   AddPartition(&manifest, "system", 10);
1135   AddPartition(&manifest, "product", 100);
1136 
1137   RunManifestValidation(
1138       manifest, kMaxSupportedMajorPayloadVersion, ErrorCode::kSuccess);
1139 }
1140 
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampFailure)1141 TEST_F(DeltaPerformerIntegrationTest, ValidatePerPartitionTimestampFailure) {
1142   // The Manifest we are validating.
1143   DeltaArchiveManifest manifest;
1144 
1145   fake_hardware_.SetVersion("system", "5");
1146   fake_hardware_.SetVersion("product", "99");
1147   fake_hardware_.SetBuildTimestamp(1);
1148 
1149   manifest.set_minor_version(kFullPayloadMinorVersion);
1150   manifest.set_max_timestamp(2);
1151   AddPartition(&manifest, "system", 10);
1152   AddPartition(&manifest, "product", 98);
1153 
1154   RunManifestValidation(manifest,
1155                         kMaxSupportedMajorPayloadVersion,
1156                         ErrorCode::kPayloadTimestampError);
1157 }
1158 
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampMissingTimestamp)1159 TEST_F(DeltaPerformerIntegrationTest,
1160        ValidatePerPartitionTimestampMissingTimestamp) {
1161   // The Manifest we are validating.
1162   DeltaArchiveManifest manifest;
1163 
1164   fake_hardware_.SetVersion("system", "5");
1165   fake_hardware_.SetVersion("product", "99");
1166   fake_hardware_.SetBuildTimestamp(1);
1167 
1168   manifest.set_minor_version(kFullPayloadMinorVersion);
1169   manifest.set_max_timestamp(2);
1170   AddPartition(&manifest, "system", 10);
1171   {
1172     auto& partition = *manifest.add_partitions();
1173     // For complete updates, missing timestamp should not trigger
1174     // timestamp error.
1175     partition.set_partition_name("product");
1176   }
1177 
1178   RunManifestValidation(
1179       manifest, kMaxSupportedMajorPayloadVersion, ErrorCode::kSuccess);
1180 }
1181 
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampPartialUpdatePass)1182 TEST_F(DeltaPerformerIntegrationTest,
1183        ValidatePerPartitionTimestampPartialUpdatePass) {
1184   fake_hardware_.SetVersion("system", "5");
1185   fake_hardware_.SetVersion("product", "99");
1186 
1187   DeltaArchiveManifest manifest;
1188   manifest.set_minor_version(kPartialUpdateMinorPayloadVersion);
1189   manifest.set_partial_update(true);
1190   AddPartition(&manifest, "product", 100);
1191   RunManifestValidation(
1192       manifest, kMaxSupportedMajorPayloadVersion, ErrorCode::kSuccess);
1193 }
1194 
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampPartialUpdateDowngrade)1195 TEST_F(DeltaPerformerIntegrationTest,
1196        ValidatePerPartitionTimestampPartialUpdateDowngrade) {
1197   fake_hardware_.SetVersion("system", "5");
1198   fake_hardware_.SetVersion("product", "99");
1199 
1200   DeltaArchiveManifest manifest;
1201   manifest.set_minor_version(kPartialUpdateMinorPayloadVersion);
1202   manifest.set_partial_update(true);
1203   AddPartition(&manifest, "product", 98);
1204   RunManifestValidation(manifest,
1205                         kMaxSupportedMajorPayloadVersion,
1206                         ErrorCode::kPayloadTimestampError);
1207 }
1208 
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampPartialUpdateMissingVersion)1209 TEST_F(DeltaPerformerIntegrationTest,
1210        ValidatePerPartitionTimestampPartialUpdateMissingVersion) {
1211   fake_hardware_.SetVersion("system", "5");
1212   fake_hardware_.SetVersion("product", "99");
1213 
1214   DeltaArchiveManifest manifest;
1215   manifest.set_minor_version(kPartialUpdateMinorPayloadVersion);
1216   manifest.set_partial_update(true);
1217   {
1218     auto& partition = *manifest.add_partitions();
1219     // For partial updates, missing timestamp should trigger an error
1220     partition.set_partition_name("product");
1221     // has_version() == false.
1222   }
1223   RunManifestValidation(manifest,
1224                         kMaxSupportedMajorPayloadVersion,
1225                         ErrorCode::kDownloadManifestParseError);
1226 }
1227 
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampPartialUpdateEmptyVersion)1228 TEST_F(DeltaPerformerIntegrationTest,
1229        ValidatePerPartitionTimestampPartialUpdateEmptyVersion) {
1230   fake_hardware_.SetVersion("system", "5");
1231   fake_hardware_.SetVersion("product", "99");
1232 
1233   DeltaArchiveManifest manifest;
1234   manifest.set_minor_version(kPartialUpdateMinorPayloadVersion);
1235   manifest.set_partial_update(true);
1236   {
1237     auto& partition = *manifest.add_partitions();
1238     // For partial updates, invalid timestamp should trigger an error
1239     partition.set_partition_name("product");
1240     partition.set_version("something");
1241   }
1242   RunManifestValidation(manifest,
1243                         kMaxSupportedMajorPayloadVersion,
1244                         ErrorCode::kDownloadManifestParseError);
1245 }
1246 
1247 }  // namespace chromeos_update_engine
1248