xref: /aosp_15_r20/system/update_engine/payload_consumer/delta_performer_unittest.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 <endian.h>
20 #include <time.h>
21 
22 #include <algorithm>
23 #include <map>
24 #include <memory>
25 #include <string>
26 #include <vector>
27 
28 #include <android-base/parseint.h>
29 #include <base/files/file_path.h>
30 #include <base/files/file_util.h>
31 #include <base/files/scoped_temp_dir.h>
32 #include <android-base/stringprintf.h>
33 #include <brillo/secure_blob.h>
34 #include <gmock/gmock.h>
35 #include <google/protobuf/repeated_field.h>
36 #include <gtest/gtest.h>
37 
38 #include "update_engine/common/constants.h"
39 #include "update_engine/common/error_code.h"
40 #include "update_engine/common/fake_boot_control.h"
41 #include "update_engine/common/fake_hardware.h"
42 #include "update_engine/common/fake_prefs.h"
43 #include "update_engine/common/hash_calculator.h"
44 #include "update_engine/common/mock_download_action.h"
45 #include "update_engine/common/test_utils.h"
46 #include "update_engine/common/testing_constants.h"
47 #include "update_engine/common/utils.h"
48 #include "update_engine/payload_consumer/mock_partition_writer.h"
49 #include "update_engine/payload_consumer/payload_constants.h"
50 #include "update_engine/payload_consumer/payload_metadata.h"
51 #include "update_engine/payload_generator/bzip.h"
52 #include "update_engine/payload_generator/extent_ranges.h"
53 #include "update_engine/payload_generator/payload_file.h"
54 #include "update_engine/payload_generator/payload_signer.h"
55 #include "update_engine/update_metadata.pb.h"
56 
57 namespace chromeos_update_engine {
58 
59 using std::string;
60 using std::vector;
61 using test_utils::GetBuildArtifactsPath;
62 using test_utils::kRandomString;
63 using testing::_;
64 using testing::Return;
65 using ::testing::Sequence;
66 
67 namespace {
68 
69 const char kBogusMetadataSignature1[] =
70     "awSFIUdUZz2VWFiR+ku0Pj00V7bPQPQFYQSXjEXr3vaw3TE4xHV5CraY3/YrZpBv"
71     "J5z4dSBskoeuaO1TNC/S6E05t+yt36tE4Fh79tMnJ/z9fogBDXWgXLEUyG78IEQr"
72     "YH6/eBsQGT2RJtBgXIXbZ9W+5G9KmGDoPOoiaeNsDuqHiBc/58OFsrxskH8E6vMS"
73     "BmMGGk82mvgzic7ApcoURbCGey1b3Mwne/hPZ/bb9CIyky8Og9IfFMdL2uAweOIR"
74     "fjoTeLYZpt+WN65Vu7jJ0cQN8e1y+2yka5112wpRf/LLtPgiAjEZnsoYpLUd7CoV"
75     "pLRtClp97kN2+tXGNBQqkA==";
76 
77 // Different options that determine what we should fill into the
78 // install_plan.metadata_signature to simulate the contents received in the
79 // Omaha response.
80 enum MetadataSignatureTest {
81   kEmptyMetadataSignature,
82   kInvalidMetadataSignature,
83   kValidMetadataSignature,
84 };
85 
86 // Compressed data without checksum, generated with:
87 // echo -n "a$(head -c 4095 /dev/zero)" | xz -9 --check=none |
88 //     hexdump -v -e '"    " 12/1 "0x%02x, " "\n"'
89 const uint8_t kXzCompressedData[] = {
90     0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x00, 0xff, 0x12, 0xd9, 0x41,
91     0x02, 0x00, 0x21, 0x01, 0x1c, 0x00, 0x00, 0x00, 0x10, 0xcf, 0x58, 0xcc,
92     0xe0, 0x0f, 0xff, 0x00, 0x1b, 0x5d, 0x00, 0x30, 0x80, 0x33, 0xff, 0xdf,
93     0xff, 0x51, 0xd6, 0xaf, 0x90, 0x1c, 0x1b, 0x4c, 0xaa, 0x3d, 0x7b, 0x28,
94     0xe4, 0x7a, 0x74, 0xbc, 0xe5, 0xa7, 0x33, 0x4e, 0xcf, 0x00, 0x00, 0x00,
95     0x00, 0x01, 0x2f, 0x80, 0x20, 0x00, 0x00, 0x00, 0x92, 0x7c, 0x7b, 0x24,
96     0xa8, 0x00, 0x0a, 0xfc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x5a,
97 };
98 
99 // clang-format off
100 const uint8_t src_deflates[] = {
101   /* raw      0  */ 0x11, 0x22,
102   /* deflate  2  */ 0x63, 0x64, 0x62, 0x66, 0x61, 0x05, 0x00,
103   /* raw      9  */ 0x33,
104   /* deflate  10 */ 0x03, 0x00,
105   /* raw      12 */
106   /* deflate  12 */ 0x63, 0x04, 0x00,
107   /* raw      15 */ 0x44, 0x55
108 };
109 
110 const uint8_t dst_deflates[] = {
111   /* deflate  0  */ 0x63, 0x64, 0x62, 0x66, 0x61, 0x05, 0x00,
112   /* raw      7  */ 0x33, 0x66,
113   /* deflate  9  */ 0x01, 0x05, 0x00, 0xFA, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05,
114   /* deflate  19 */ 0x63, 0x04, 0x00
115 };
116 // clang-format on
117 
118 // To generate this patch either:
119 // - Use puffin/src/patching_unittest.cc:TestPatching
120 // Or
121 // - Use the following approach:
122 // * Make src_deflate a string of hex with only spaces. (e.g. "0XTE 0xST")
123 // * echo "0XTE 0xST" | xxd -r -p > src.bin
124 // * Find the location of deflates in src_deflates (in bytes) in the format of
125 //   "offset:length,...". (e.g. "2:7,10:2,12:3")
126 // * Do previous three steps for dst_deflates.
127 // * puffin --operation=puffdiff --src_file=src.bin --dst_file=dst.bin \
128 //   --src_deflates_byte="2:7,10:2,12:3" --dst_deflates_byte="0:7,9:10,19:3" \
129 //   --patch_file=patch.bin
130 // * hexdump -ve '"  " 12/1 "0x%02x, " "\n"' patch.bin
131 const uint8_t puffdiff_patch[] = {
132     0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x51, 0x08, 0x01, 0x12, 0x27,
133     0x0A, 0x04, 0x08, 0x10, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x50, 0x10, 0x0A,
134     0x0A, 0x04, 0x08, 0x60, 0x10, 0x12, 0x12, 0x04, 0x08, 0x10, 0x10, 0x58,
135     0x12, 0x04, 0x08, 0x78, 0x10, 0x28, 0x12, 0x05, 0x08, 0xA8, 0x01, 0x10,
136     0x38, 0x18, 0x1F, 0x1A, 0x24, 0x0A, 0x02, 0x10, 0x32, 0x0A, 0x04, 0x08,
137     0x48, 0x10, 0x50, 0x0A, 0x05, 0x08, 0x98, 0x01, 0x10, 0x12, 0x12, 0x02,
138     0x10, 0x58, 0x12, 0x04, 0x08, 0x70, 0x10, 0x58, 0x12, 0x05, 0x08, 0xC8,
139     0x01, 0x10, 0x38, 0x18, 0x21, 0x42, 0x53, 0x44, 0x49, 0x46, 0x46, 0x34,
140     0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00,
141     0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142     0x00, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0x65,
143     0x29, 0x8C, 0x9B, 0x00, 0x00, 0x03, 0x60, 0x40, 0x7A, 0x0E, 0x08, 0x00,
144     0x40, 0x00, 0x20, 0x00, 0x21, 0x22, 0x9A, 0x3D, 0x4F, 0x50, 0x40, 0x0C,
145     0x3B, 0xC7, 0x9B, 0xB2, 0x21, 0x0E, 0xE9, 0x15, 0x98, 0x7A, 0x7C, 0x5D,
146     0xC9, 0x14, 0xE1, 0x42, 0x41, 0x94, 0xA6, 0x32, 0x6C, 0x42, 0x5A, 0x68,
147     0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xF1, 0x20, 0x5F, 0x0D, 0x00,
148     0x00, 0x02, 0x41, 0x15, 0x42, 0x08, 0x20, 0x00, 0x40, 0x00, 0x00, 0x02,
149     0x40, 0x00, 0x20, 0x00, 0x22, 0x3D, 0x23, 0x10, 0x86, 0x03, 0x96, 0x54,
150     0x11, 0x16, 0x5F, 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0xF1, 0x20, 0x5F,
151     0x0D, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0x07,
152     0xD4, 0xCB, 0x6E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x20, 0x00,
153     0x21, 0x18, 0x46, 0x82, 0xEE, 0x48, 0xA7, 0x0A, 0x12, 0x00, 0xFA, 0x99,
154     0x6D, 0xC0};
155 
156 }  // namespace
157 
158 class DeltaPerformerTest : public ::testing::Test {
159  protected:
SetUp()160   void SetUp() override {
161     install_plan_.source_slot = 0;
162     install_plan_.target_slot = 1;
163     EXPECT_CALL(mock_delegate_, ShouldCancel(_))
164         .WillRepeatedly(testing::Return(false));
165     // Set the public key corresponding to the unittest private key.
166     string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath);
167     EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
168     performer_.set_public_key_path(public_key_path);
169   }
170 
171   // Test helper placed where it can easily be friended from DeltaPerformer.
RunManifestValidation(const DeltaArchiveManifest & manifest,uint64_t major_version,InstallPayloadType payload_type,ErrorCode expected)172   void RunManifestValidation(const DeltaArchiveManifest& manifest,
173                              uint64_t major_version,
174                              InstallPayloadType payload_type,
175                              ErrorCode expected) {
176     payload_.type = payload_type;
177 
178     // The Manifest we are validating.
179     performer_.manifest_.CopyFrom(manifest);
180     performer_.major_payload_version_ = major_version;
181 
182     EXPECT_EQ(expected, performer_.ValidateManifest());
183   }
184 
GeneratePayload(const brillo::Blob & blob_data,const vector<AnnotatedOperation> & aops,bool sign_payload,PartitionConfig * old_part=nullptr)185   brillo::Blob GeneratePayload(const brillo::Blob& blob_data,
186                                const vector<AnnotatedOperation>& aops,
187                                bool sign_payload,
188                                PartitionConfig* old_part = nullptr) {
189     return GeneratePayload(blob_data,
190                            aops,
191                            sign_payload,
192                            kMaxSupportedMajorPayloadVersion,
193                            kMaxSupportedMinorPayloadVersion,
194                            old_part);
195   }
196 
GeneratePayload(const brillo::Blob & blob_data,const vector<AnnotatedOperation> & aops,bool sign_payload,uint64_t major_version,uint32_t minor_version,PartitionConfig * old_part=nullptr)197   brillo::Blob GeneratePayload(const brillo::Blob& blob_data,
198                                const vector<AnnotatedOperation>& aops,
199                                bool sign_payload,
200                                uint64_t major_version,
201                                uint32_t minor_version,
202                                PartitionConfig* old_part = nullptr) {
203     ScopedTempFile blob_file("Blob-XXXXXX");
204     EXPECT_TRUE(test_utils::WriteFileVector(blob_file.path(), blob_data));
205 
206     PayloadGenerationConfig config;
207     config.version.major = major_version;
208     config.version.minor = minor_version;
209 
210     PayloadFile payload;
211     EXPECT_TRUE(payload.Init(config));
212 
213     std::unique_ptr<PartitionConfig> old_part_uptr;
214     if (!old_part) {
215       old_part_uptr = std::make_unique<PartitionConfig>(kPartitionNameRoot);
216       old_part = old_part_uptr.get();
217     }
218     if (minor_version != kFullPayloadMinorVersion) {
219       // When generating a delta payload we need to include the old partition
220       // information to mark it as a delta payload.
221       if (old_part->path.empty()) {
222         old_part->path = "/dev/null";
223       }
224     }
225     PartitionConfig new_part(kPartitionNameRoot);
226     new_part.path = "/dev/zero";
227     new_part.size = 1234;
228 
229     payload.AddPartition(*old_part, new_part, aops, {}, {});
230 
231     // We include a kernel partition without operations.
232     old_part->name = kPartitionNameKernel;
233     new_part.name = kPartitionNameKernel;
234     new_part.size = 0;
235 
236     payload.AddPartition(*old_part, new_part, {}, {}, {});
237 
238     ScopedTempFile payload_file("Payload-XXXXXX");
239     string private_key =
240         sign_payload ? GetBuildArtifactsPath(kUnittestPrivateKeyPath) : "";
241     EXPECT_TRUE(payload.WritePayload(payload_file.path(),
242                                      blob_file.path(),
243                                      private_key,
244                                      &payload_.metadata_size));
245 
246     brillo::Blob payload_data;
247     EXPECT_TRUE(utils::ReadFile(payload_file.path(), &payload_data));
248     return payload_data;
249   }
250 
GenerateSourceCopyPayload(const brillo::Blob & copied_data,bool add_hash,PartitionConfig * old_part=nullptr)251   brillo::Blob GenerateSourceCopyPayload(const brillo::Blob& copied_data,
252                                          bool add_hash,
253                                          PartitionConfig* old_part = nullptr) {
254     PayloadGenerationConfig config;
255     const uint64_t kDefaultBlockSize = config.block_size;
256     EXPECT_EQ(0U, copied_data.size() % kDefaultBlockSize);
257     uint64_t num_blocks = copied_data.size() / kDefaultBlockSize;
258     AnnotatedOperation aop;
259     *(aop.op.add_src_extents()) = ExtentForRange(0, num_blocks);
260     *(aop.op.add_dst_extents()) = ExtentForRange(0, num_blocks);
261     aop.op.set_type(InstallOperation::SOURCE_COPY);
262     brillo::Blob src_hash;
263     EXPECT_TRUE(HashCalculator::RawHashOfData(copied_data, &src_hash));
264     if (add_hash)
265       aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
266 
267     return GeneratePayload(brillo::Blob(), {aop}, false, old_part);
268   }
269 
270   // Apply |payload_data| on partition specified in |source_path|.
271   // Expect result of performer_.Write() to be |expect_success|.
272   // Returns the result of the payload application.
ApplyPayload(const brillo::Blob & payload_data,const string & source_path,bool expect_success)273   brillo::Blob ApplyPayload(const brillo::Blob& payload_data,
274                             const string& source_path,
275                             bool expect_success) {
276     return ApplyPayloadToData(
277         &performer_, payload_data, source_path, brillo::Blob(), expect_success);
278   }
ApplyPayloadToData(const brillo::Blob & payload_data,const string & source_path,const brillo::Blob & target_data,bool expect_success)279   brillo::Blob ApplyPayloadToData(const brillo::Blob& payload_data,
280                                   const string& source_path,
281                                   const brillo::Blob& target_data,
282                                   bool expect_success) {
283     return ApplyPayloadToData(
284         &performer_, payload_data, source_path, target_data, expect_success);
285   }
286 
287   // Apply the payload provided in |payload_data| reading from the |source_path|
288   // file and writing the contents to a new partition. The existing data in the
289   // new target file are set to |target_data| before applying the payload.
290   // Expect result of performer_.Write() to be |expect_success|.
291   // Returns the result of the payload application.
ApplyPayloadToData(DeltaPerformer * delta_performer,const brillo::Blob & payload_data,const string & source_path,const brillo::Blob & target_data,bool expect_success)292   brillo::Blob ApplyPayloadToData(DeltaPerformer* delta_performer,
293                                   const brillo::Blob& payload_data,
294                                   const string& source_path,
295                                   const brillo::Blob& target_data,
296                                   bool expect_success) {
297     ScopedTempFile new_part("Partition-XXXXXX");
298     EXPECT_TRUE(test_utils::WriteFileVector(new_part.path(), target_data));
299 
300     payload_.size = payload_data.size();
301     // We installed the operations only in the rootfs partition, but the
302     // delta performer needs to access all the partitions.
303     fake_boot_control_.SetPartitionDevice(
304         kPartitionNameRoot, install_plan_.target_slot, new_part.path());
305     fake_boot_control_.SetPartitionDevice(
306         kPartitionNameRoot, install_plan_.source_slot, source_path);
307     fake_boot_control_.SetPartitionDevice(
308         kPartitionNameKernel, install_plan_.target_slot, "/dev/null");
309     fake_boot_control_.SetPartitionDevice(
310         kPartitionNameKernel, install_plan_.source_slot, "/dev/null");
311 
312     EXPECT_EQ(expect_success,
313               delta_performer->Write(payload_data.data(), payload_data.size()));
314     EXPECT_EQ(0, performer_.Close());
315 
316     brillo::Blob partition_data;
317     EXPECT_TRUE(utils::ReadFile(new_part.path(), &partition_data));
318     return partition_data;
319   }
320 
321   // Calls delta performer's Write method by pretending to pass in bytes from a
322   // delta file whose metadata size is actual_metadata_size and tests if all
323   // checks are correctly performed if the install plan contains
324   // expected_metadata_size and that the result of the parsing are as per
325   // hash_checks_mandatory flag.
DoMetadataSizeTest(uint64_t expected_metadata_size,uint64_t actual_metadata_size,bool hash_checks_mandatory)326   void DoMetadataSizeTest(uint64_t expected_metadata_size,
327                           uint64_t actual_metadata_size,
328                           bool hash_checks_mandatory) {
329     install_plan_.hash_checks_mandatory = hash_checks_mandatory;
330 
331     // Set a valid magic string and version number 1.
332     EXPECT_TRUE(performer_.Write("CrAU", 4));
333     uint64_t version = htobe64(kBrilloMajorPayloadVersion);
334     EXPECT_TRUE(performer_.Write(&version, 8));
335 
336     payload_.metadata_size = expected_metadata_size;
337     payload_.size = actual_metadata_size + 1;
338     ErrorCode error_code{};
339     // When filling in size in manifest, exclude the size of the 24-byte header.
340     uint64_t size_in_manifest = htobe64(actual_metadata_size - 24);
341     performer_.Write(&size_in_manifest, 8, &error_code);
342     auto signature_size = htobe64(10);
343     bool result = performer_.Write(&signature_size, 4, &error_code);
344     if (expected_metadata_size == actual_metadata_size ||
345         !hash_checks_mandatory) {
346       EXPECT_TRUE(result);
347     } else {
348       EXPECT_FALSE(result);
349       EXPECT_EQ(ErrorCode::kDownloadInvalidMetadataSize, error_code);
350     }
351 
352     EXPECT_LT(performer_.Close(), 0);
353   }
354 
355   // Generates a valid delta file but tests the delta performer by supplying
356   // different metadata signatures as per metadata_signature_test flag and
357   // sees if the result of the parsing are as per hash_checks_mandatory flag.
DoMetadataSignatureTest(MetadataSignatureTest metadata_signature_test,bool sign_payload,bool hash_checks_mandatory)358   void DoMetadataSignatureTest(MetadataSignatureTest metadata_signature_test,
359                                bool sign_payload,
360                                bool hash_checks_mandatory) {
361     // Loads the payload and parses the manifest.
362     brillo::Blob payload = GeneratePayload(brillo::Blob(),
363                                            vector<AnnotatedOperation>(),
364                                            sign_payload,
365                                            kBrilloMajorPayloadVersion,
366                                            kFullPayloadMinorVersion);
367 
368     payload_.size = payload.size();
369     LOG(INFO) << "Payload size: " << payload.size();
370 
371     install_plan_.hash_checks_mandatory = hash_checks_mandatory;
372 
373     MetadataParseResult expected_result{}, actual_result{};
374     ErrorCode expected_error{}, actual_error{};
375 
376     // Fill up the metadata signature in install plan according to the test.
377     switch (metadata_signature_test) {
378       case kEmptyMetadataSignature:
379         payload_.metadata_signature.clear();
380         // We need to set the signature size in a signed payload to zero.
381         std::fill(
382             std::next(payload.begin(), 20), std::next(payload.begin(), 24), 0);
383         expected_result = MetadataParseResult::kError;
384         expected_error = ErrorCode::kDownloadMetadataSignatureMissingError;
385         break;
386 
387       case kInvalidMetadataSignature:
388         payload_.metadata_signature = kBogusMetadataSignature1;
389         expected_result = MetadataParseResult::kError;
390         expected_error = ErrorCode::kDownloadMetadataSignatureMismatch;
391         break;
392 
393       case kValidMetadataSignature:
394       default:
395         // Set the install plan's metadata size to be the same as the one
396         // in the manifest so that we pass the metadata size checks. Only
397         // then we can get to manifest signature checks.
398         ASSERT_TRUE(PayloadSigner::GetMetadataSignature(
399             payload.data(),
400             payload_.metadata_size,
401             GetBuildArtifactsPath(kUnittestPrivateKeyPath),
402             &payload_.metadata_signature));
403         EXPECT_FALSE(payload_.metadata_signature.empty());
404         expected_result = MetadataParseResult::kSuccess;
405         expected_error = ErrorCode::kSuccess;
406         break;
407     }
408 
409     // Ignore the expected result/error if hash checks are not mandatory.
410     if (!hash_checks_mandatory) {
411       expected_result = MetadataParseResult::kSuccess;
412       expected_error = ErrorCode::kSuccess;
413     }
414 
415     // Init actual_error with an invalid value so that we make sure
416     // ParsePayloadMetadata properly populates it in all cases.
417     actual_error = ErrorCode::kUmaReportedMax;
418     actual_result = performer_.ParsePayloadMetadata(payload, &actual_error);
419 
420     EXPECT_EQ(expected_result, actual_result);
421     EXPECT_EQ(expected_error, actual_error);
422 
423     // Check that the parsed metadata size is what's expected. This test
424     // implicitly confirms that the metadata signature is valid, if required.
425     EXPECT_EQ(payload_.metadata_size, performer_.metadata_size_);
426   }
427 
428   FakePrefs prefs_;
429   InstallPlan install_plan_;
430   InstallPlan::Payload payload_;
431   FakeBootControl fake_boot_control_;
432   FakeHardware fake_hardware_;
433   MockDownloadActionDelegate mock_delegate_;
434   FileDescriptorPtr fake_ecc_fd_;
435   DeltaPerformer performer_{&prefs_,
436                             &fake_boot_control_,
437                             &fake_hardware_,
438                             &mock_delegate_,
439                             &install_plan_,
440                             &payload_,
441                             false /* interactive */,
442                             "" /* Update certs path */};
443 };
444 
TEST_F(DeltaPerformerTest,FullPayloadWriteTest)445 TEST_F(DeltaPerformerTest, FullPayloadWriteTest) {
446   payload_.type = InstallPayloadType::kFull;
447   brillo::Blob expected_data =
448       brillo::Blob(std::begin(kRandomString), std::end(kRandomString));
449   expected_data.resize(4096);  // block size
450   vector<AnnotatedOperation> aops;
451   AnnotatedOperation aop;
452   *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
453   aop.op.set_data_offset(0);
454   aop.op.set_data_length(expected_data.size());
455   aop.op.set_type(InstallOperation::REPLACE);
456   aops.push_back(aop);
457 
458   brillo::Blob payload_data = GeneratePayload(expected_data,
459                                               aops,
460                                               false,
461                                               kBrilloMajorPayloadVersion,
462                                               kFullPayloadMinorVersion);
463 
464   EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true));
465 }
466 
TEST_F(DeltaPerformerTest,ShouldCancelTest)467 TEST_F(DeltaPerformerTest, ShouldCancelTest) {
468   payload_.type = InstallPayloadType::kFull;
469   brillo::Blob expected_data =
470       brillo::Blob(std::begin(kRandomString), std::end(kRandomString));
471   expected_data.resize(4096);  // block size
472   vector<AnnotatedOperation> aops;
473   AnnotatedOperation aop;
474   *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
475   aop.op.set_data_offset(0);
476   aop.op.set_data_length(expected_data.size());
477   aop.op.set_type(InstallOperation::REPLACE);
478   aops.push_back(aop);
479 
480   brillo::Blob payload_data = GeneratePayload(expected_data,
481                                               aops,
482                                               false,
483                                               kBrilloMajorPayloadVersion,
484                                               kFullPayloadMinorVersion);
485 
486   testing::Mock::VerifyAndClearExpectations(&mock_delegate_);
487   EXPECT_CALL(mock_delegate_, ShouldCancel(_))
488       .WillOnce(testing::DoAll(testing::SetArgPointee<0>(ErrorCode::kError),
489                                testing::Return(true)));
490 
491   ApplyPayload(payload_data, "/dev/null", false);
492 }
493 
TEST_F(DeltaPerformerTest,ReplaceOperationTest)494 TEST_F(DeltaPerformerTest, ReplaceOperationTest) {
495   brillo::Blob expected_data =
496       brillo::Blob(std::begin(kRandomString), std::end(kRandomString));
497   expected_data.resize(4096);  // block size
498   vector<AnnotatedOperation> aops;
499   AnnotatedOperation aop;
500   *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
501   aop.op.set_data_offset(0);
502   aop.op.set_data_length(expected_data.size());
503   aop.op.set_type(InstallOperation::REPLACE);
504   aops.push_back(aop);
505 
506   brillo::Blob payload_data = GeneratePayload(expected_data, aops, false);
507 
508   EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true));
509 }
510 
TEST_F(DeltaPerformerTest,ReplaceBzOperationTest)511 TEST_F(DeltaPerformerTest, ReplaceBzOperationTest) {
512   brillo::Blob expected_data =
513       brillo::Blob(std::begin(kRandomString), std::end(kRandomString));
514   expected_data.resize(4096);  // block size
515   brillo::Blob bz_data;
516   EXPECT_TRUE(BzipCompress(expected_data, &bz_data));
517 
518   vector<AnnotatedOperation> aops;
519   AnnotatedOperation aop;
520   *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
521   aop.op.set_data_offset(0);
522   aop.op.set_data_length(bz_data.size());
523   aop.op.set_type(InstallOperation::REPLACE_BZ);
524   aops.push_back(aop);
525 
526   brillo::Blob payload_data = GeneratePayload(bz_data, aops, false);
527 
528   EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true));
529 }
530 
TEST_F(DeltaPerformerTest,ReplaceXzOperationTest)531 TEST_F(DeltaPerformerTest, ReplaceXzOperationTest) {
532   brillo::Blob xz_data(std::begin(kXzCompressedData),
533                        std::end(kXzCompressedData));
534   // The compressed xz data contains a single "a" and padded with zero for the
535   // rest of the block.
536   brillo::Blob expected_data = brillo::Blob(4096, 0);
537   expected_data[0] = 'a';
538 
539   AnnotatedOperation aop;
540   *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
541   aop.op.set_data_offset(0);
542   aop.op.set_data_length(xz_data.size());
543   aop.op.set_type(InstallOperation::REPLACE_XZ);
544   vector<AnnotatedOperation> aops = {aop};
545 
546   brillo::Blob payload_data = GeneratePayload(xz_data, aops, false);
547 
548   EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true));
549 }
550 
TEST_F(DeltaPerformerTest,ZeroOperationTest)551 TEST_F(DeltaPerformerTest, ZeroOperationTest) {
552   brillo::Blob existing_data = brillo::Blob(4096 * 10, 'a');
553   brillo::Blob expected_data = existing_data;
554   // Blocks 4, 5 and 7 should have zeros instead of 'a' after the operation is
555   // applied.
556   std::fill(
557       expected_data.data() + 4096 * 4, expected_data.data() + 4096 * 6, 0);
558   std::fill(
559       expected_data.data() + 4096 * 7, expected_data.data() + 4096 * 8, 0);
560 
561   AnnotatedOperation aop;
562   *(aop.op.add_dst_extents()) = ExtentForRange(4, 2);
563   *(aop.op.add_dst_extents()) = ExtentForRange(7, 1);
564   aop.op.set_type(InstallOperation::ZERO);
565   vector<AnnotatedOperation> aops = {aop};
566 
567   brillo::Blob payload_data = GeneratePayload(brillo::Blob(), aops, false);
568 
569   EXPECT_EQ(expected_data,
570             ApplyPayloadToData(payload_data, "/dev/null", existing_data, true));
571 }
572 
TEST_F(DeltaPerformerTest,SourceCopyOperationTest)573 TEST_F(DeltaPerformerTest, SourceCopyOperationTest) {
574   brillo::Blob expected_data(std::begin(kRandomString),
575                              std::end(kRandomString));
576   expected_data.resize(4096);  // block size
577   AnnotatedOperation aop;
578   *(aop.op.add_src_extents()) = ExtentForRange(0, 1);
579   *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
580   aop.op.set_type(InstallOperation::SOURCE_COPY);
581   brillo::Blob src_hash;
582   EXPECT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash));
583   aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
584 
585   ScopedTempFile source("Source-XXXXXX");
586   EXPECT_TRUE(test_utils::WriteFileVector(source.path(), expected_data));
587 
588   PartitionConfig old_part(kPartitionNameRoot);
589   old_part.path = source.path();
590   old_part.size = expected_data.size();
591 
592   brillo::Blob payload_data =
593       GeneratePayload(brillo::Blob(), {aop}, false, &old_part);
594 
595   EXPECT_EQ(expected_data, ApplyPayload(payload_data, source.path(), true));
596 }
597 
TEST_F(DeltaPerformerTest,PuffdiffOperationTest)598 TEST_F(DeltaPerformerTest, PuffdiffOperationTest) {
599   AnnotatedOperation aop;
600   *(aop.op.add_src_extents()) = ExtentForRange(0, 1);
601   *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
602   brillo::Blob puffdiff_payload(std::begin(puffdiff_patch),
603                                 std::end(puffdiff_patch));
604   aop.op.set_data_offset(0);
605   aop.op.set_data_length(puffdiff_payload.size());
606   aop.op.set_type(InstallOperation::PUFFDIFF);
607   brillo::Blob src(std::begin(src_deflates), std::end(src_deflates));
608   src.resize(4096);  // block size
609   brillo::Blob src_hash;
610   EXPECT_TRUE(HashCalculator::RawHashOfData(src, &src_hash));
611   aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
612 
613   ScopedTempFile source("Source-XXXXXX");
614   EXPECT_TRUE(test_utils::WriteFileVector(source.path(), src));
615 
616   PartitionConfig old_part(kPartitionNameRoot);
617   old_part.path = source.path();
618   old_part.size = src.size();
619 
620   brillo::Blob payload_data =
621       GeneratePayload(puffdiff_payload, {aop}, false, &old_part);
622 
623   brillo::Blob dst(std::begin(dst_deflates), std::end(dst_deflates));
624   EXPECT_EQ(dst, ApplyPayload(payload_data, source.path(), true));
625 }
626 
TEST_F(DeltaPerformerTest,SourceHashMismatchTest)627 TEST_F(DeltaPerformerTest, SourceHashMismatchTest) {
628   brillo::Blob expected_data = {'f', 'o', 'o'};
629   brillo::Blob actual_data = {'b', 'a', 'r'};
630   expected_data.resize(4096);  // block size
631   actual_data.resize(4096);    // block size
632 
633   AnnotatedOperation aop;
634   *(aop.op.add_src_extents()) = ExtentForRange(0, 1);
635   *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
636   aop.op.set_type(InstallOperation::SOURCE_COPY);
637   brillo::Blob src_hash;
638   EXPECT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash));
639   aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
640 
641   ScopedTempFile source("Source-XXXXXX");
642   EXPECT_TRUE(test_utils::WriteFileVector(source.path(), actual_data));
643 
644   PartitionConfig old_part(kPartitionNameRoot);
645   old_part.path = source.path();
646   old_part.size = actual_data.size();
647 
648   brillo::Blob payload_data =
649       GeneratePayload(brillo::Blob(), {aop}, false, &old_part);
650 
651   // When source hash mismatches, PartitionWriter will refuse to write anything.
652   // Therefore we should expect an empty blob.
653   EXPECT_EQ(brillo::Blob{}, ApplyPayload(payload_data, source.path(), false));
654 }
655 
TEST_F(DeltaPerformerTest,ExtentsToByteStringTest)656 TEST_F(DeltaPerformerTest, ExtentsToByteStringTest) {
657   uint64_t test[] = {1, 1, 4, 2, 0, 1};
658   static_assert(std::size(test) % 2 == 0, "Array size uneven");
659   const uint64_t block_size = 4096;
660   const uint64_t file_length = 4 * block_size - 13;
661 
662   google::protobuf::RepeatedPtrField<Extent> extents;
663   for (size_t i = 0; i < std::size(test); i += 2) {
664     *(extents.Add()) = ExtentForRange(test[i], test[i + 1]);
665   }
666 
667   string expected_output = "4096:4096,16384:8192,0:4083";
668   string actual_output;
669   EXPECT_TRUE(DeltaPerformer::ExtentsToBsdiffPositionsString(
670       extents, block_size, file_length, &actual_output));
671   EXPECT_EQ(expected_output, actual_output);
672 }
673 
TEST_F(DeltaPerformerTest,ValidateManifestFullGoodTest)674 TEST_F(DeltaPerformerTest, ValidateManifestFullGoodTest) {
675   // The Manifest we are validating.
676   DeltaArchiveManifest manifest;
677   for (const auto& part_name : {"kernel", "rootfs"}) {
678     auto part = manifest.add_partitions();
679     part->set_partition_name(part_name);
680     part->mutable_new_partition_info();
681   }
682   manifest.set_minor_version(kFullPayloadMinorVersion);
683 
684   RunManifestValidation(manifest,
685                         kBrilloMajorPayloadVersion,
686                         InstallPayloadType::kFull,
687                         ErrorCode::kSuccess);
688 }
689 
TEST_F(DeltaPerformerTest,ValidateManifestDeltaMaxGoodTest)690 TEST_F(DeltaPerformerTest, ValidateManifestDeltaMaxGoodTest) {
691   // The Manifest we are validating.
692   DeltaArchiveManifest manifest;
693   for (const auto& part_name : {"kernel", "rootfs"}) {
694     auto part = manifest.add_partitions();
695     part->set_partition_name(part_name);
696     part->mutable_old_partition_info();
697     part->mutable_new_partition_info();
698   }
699   manifest.set_minor_version(kMaxSupportedMinorPayloadVersion);
700 
701   RunManifestValidation(manifest,
702                         kBrilloMajorPayloadVersion,
703                         InstallPayloadType::kDelta,
704                         ErrorCode::kSuccess);
705 }
706 
TEST_F(DeltaPerformerTest,ValidateManifestDeltaMinGoodTest)707 TEST_F(DeltaPerformerTest, ValidateManifestDeltaMinGoodTest) {
708   // The Manifest we are validating.
709   DeltaArchiveManifest manifest;
710   for (const auto& part_name : {"kernel", "rootfs"}) {
711     auto part = manifest.add_partitions();
712     part->set_partition_name(part_name);
713     part->mutable_old_partition_info();
714     part->mutable_new_partition_info();
715   }
716   manifest.set_minor_version(kMinSupportedMinorPayloadVersion);
717 
718   RunManifestValidation(manifest,
719                         kBrilloMajorPayloadVersion,
720                         InstallPayloadType::kDelta,
721                         ErrorCode::kSuccess);
722 }
723 
TEST_F(DeltaPerformerTest,ValidateManifestFullUnsetMinorVersion)724 TEST_F(DeltaPerformerTest, ValidateManifestFullUnsetMinorVersion) {
725   // The Manifest we are validating.
726   DeltaArchiveManifest manifest;
727 
728   RunManifestValidation(manifest,
729                         kMaxSupportedMajorPayloadVersion,
730                         InstallPayloadType::kFull,
731                         ErrorCode::kSuccess);
732 }
733 
TEST_F(DeltaPerformerTest,ValidateManifestDeltaUnsetMinorVersion)734 TEST_F(DeltaPerformerTest, ValidateManifestDeltaUnsetMinorVersion) {
735   // The Manifest we are validating.
736   DeltaArchiveManifest manifest;
737   // Add an empty rootfs partition info to trick the DeltaPerformer into think
738   // that this is a delta payload manifest with a missing minor version.
739   auto rootfs = manifest.add_partitions();
740   rootfs->set_partition_name("rootfs");
741   rootfs->mutable_old_partition_info();
742 
743   RunManifestValidation(manifest,
744                         kMaxSupportedMajorPayloadVersion,
745                         InstallPayloadType::kDelta,
746                         ErrorCode::kUnsupportedMinorPayloadVersion);
747 }
748 
TEST_F(DeltaPerformerTest,ValidateManifestFullOldKernelTest)749 TEST_F(DeltaPerformerTest, ValidateManifestFullOldKernelTest) {
750   // The Manifest we are validating.
751   DeltaArchiveManifest manifest;
752   for (const auto& part_name : {"kernel", "rootfs"}) {
753     auto part = manifest.add_partitions();
754     part->set_partition_name(part_name);
755     part->mutable_old_partition_info();
756     part->mutable_new_partition_info();
757   }
758   manifest.mutable_partitions(0)->clear_old_partition_info();
759   RunManifestValidation(manifest,
760                         kBrilloMajorPayloadVersion,
761                         InstallPayloadType::kFull,
762                         ErrorCode::kPayloadMismatchedType);
763 }
764 
TEST_F(DeltaPerformerTest,ValidateManifestFullPartitionUpdateTest)765 TEST_F(DeltaPerformerTest, ValidateManifestFullPartitionUpdateTest) {
766   // The Manifest we are validating.
767   DeltaArchiveManifest manifest;
768   PartitionUpdate* partition = manifest.add_partitions();
769   partition->mutable_old_partition_info();
770   partition->mutable_new_partition_info();
771   manifest.set_minor_version(kMaxSupportedMinorPayloadVersion);
772 
773   RunManifestValidation(manifest,
774                         kBrilloMajorPayloadVersion,
775                         InstallPayloadType::kFull,
776                         ErrorCode::kPayloadMismatchedType);
777 }
778 
TEST_F(DeltaPerformerTest,ValidateManifestBadMinorVersion)779 TEST_F(DeltaPerformerTest, ValidateManifestBadMinorVersion) {
780   // The Manifest we are validating.
781   DeltaArchiveManifest manifest;
782 
783   // Generate a bad version number.
784   manifest.set_minor_version(kMaxSupportedMinorPayloadVersion + 10000);
785   // Mark the manifest as a delta payload by setting |old_partition_info|.
786   manifest.add_partitions()->mutable_old_partition_info();
787 
788   RunManifestValidation(manifest,
789                         kMaxSupportedMajorPayloadVersion,
790                         InstallPayloadType::kDelta,
791                         ErrorCode::kUnsupportedMinorPayloadVersion);
792 }
793 
TEST_F(DeltaPerformerTest,ValidateManifestDowngrade)794 TEST_F(DeltaPerformerTest, ValidateManifestDowngrade) {
795   // The Manifest we are validating.
796   DeltaArchiveManifest manifest;
797 
798   manifest.set_minor_version(kFullPayloadMinorVersion);
799   manifest.set_max_timestamp(1);
800   fake_hardware_.SetBuildTimestamp(2);
801 
802   RunManifestValidation(manifest,
803                         kMaxSupportedMajorPayloadVersion,
804                         InstallPayloadType::kFull,
805                         ErrorCode::kPayloadTimestampError);
806 }
807 
TEST_F(DeltaPerformerTest,ValidatePerPartitionTimestampSuccess)808 TEST_F(DeltaPerformerTest, ValidatePerPartitionTimestampSuccess) {
809   // The Manifest we are validating.
810   DeltaArchiveManifest manifest;
811 
812   manifest.set_minor_version(kFullPayloadMinorVersion);
813   manifest.set_max_timestamp(2);
814   fake_hardware_.SetBuildTimestamp(1);
815   auto& partition = *manifest.add_partitions();
816   partition.set_version("10");
817   partition.set_partition_name("system");
818   fake_hardware_.SetVersion("system", "5");
819 
820   RunManifestValidation(manifest,
821                         kMaxSupportedMajorPayloadVersion,
822                         InstallPayloadType::kFull,
823                         ErrorCode::kSuccess);
824 }
825 
TEST_F(DeltaPerformerTest,BrilloMetadataSignatureSizeTest)826 TEST_F(DeltaPerformerTest, BrilloMetadataSignatureSizeTest) {
827   unsigned int seed = time(nullptr);
828   EXPECT_TRUE(performer_.Write(kDeltaMagic, sizeof(kDeltaMagic)));
829 
830   uint64_t major_version = htobe64(kBrilloMajorPayloadVersion);
831   EXPECT_TRUE(
832       performer_.Write(&major_version, PayloadMetadata::kDeltaVersionSize));
833 
834   uint64_t manifest_size = rand_r(&seed) % 256;
835   uint32_t metadata_signature_size = rand_r(&seed) % 256;
836 
837   // The payload size has to be bigger than the |metadata_size| and
838   // |metadata_signature_size|
839   payload_.size = PayloadMetadata::kDeltaManifestSizeOffset +
840                   PayloadMetadata::kDeltaManifestSizeSize +
841                   PayloadMetadata::kDeltaMetadataSignatureSizeSize +
842                   manifest_size + metadata_signature_size + 1;
843 
844   uint64_t manifest_size_be = htobe64(manifest_size);
845   EXPECT_TRUE(performer_.Write(&manifest_size_be,
846                                PayloadMetadata::kDeltaManifestSizeSize));
847 
848   uint32_t metadata_signature_size_be = htobe32(metadata_signature_size);
849   EXPECT_TRUE(
850       performer_.Write(&metadata_signature_size_be,
851                        PayloadMetadata::kDeltaMetadataSignatureSizeSize));
852 
853   EXPECT_LT(performer_.Close(), 0);
854 
855   EXPECT_TRUE(performer_.IsHeaderParsed());
856   EXPECT_EQ(kBrilloMajorPayloadVersion, performer_.major_payload_version_);
857   EXPECT_EQ(24 + manifest_size, performer_.metadata_size_);  // 4 + 8 + 8 + 4
858   EXPECT_EQ(metadata_signature_size, performer_.metadata_signature_size_);
859 }
860 
TEST_F(DeltaPerformerTest,BrilloMetadataSizeNOKTest)861 TEST_F(DeltaPerformerTest, BrilloMetadataSizeNOKTest) {
862   unsigned int seed = time(nullptr);
863   EXPECT_TRUE(performer_.Write(kDeltaMagic, sizeof(kDeltaMagic)));
864 
865   uint64_t major_version = htobe64(kBrilloMajorPayloadVersion);
866   EXPECT_TRUE(
867       performer_.Write(&major_version, PayloadMetadata::kDeltaVersionSize));
868 
869   uint64_t manifest_size = UINT64_MAX - 600;  // Subtract to avoid wrap around.
870   uint64_t manifest_offset = PayloadMetadata::kDeltaManifestSizeOffset +
871                              PayloadMetadata::kDeltaManifestSizeSize +
872                              PayloadMetadata::kDeltaMetadataSignatureSizeSize;
873   payload_.metadata_size = manifest_offset + manifest_size;
874   uint32_t metadata_signature_size = rand_r(&seed) % 256;
875 
876   // The payload size is greater than the payload header but smaller than
877   // |metadata_signature_size| + |metadata_size|
878   payload_.size = manifest_offset + metadata_signature_size + 1;
879 
880   uint64_t manifest_size_be = htobe64(manifest_size);
881   EXPECT_TRUE(performer_.Write(&manifest_size_be,
882                                PayloadMetadata::kDeltaManifestSizeSize));
883   uint32_t metadata_signature_size_be = htobe32(metadata_signature_size);
884 
885   ErrorCode error{};
886   EXPECT_FALSE(
887       performer_.Write(&metadata_signature_size_be,
888                        PayloadMetadata::kDeltaMetadataSignatureSizeSize + 1,
889                        &error));
890 
891   EXPECT_EQ(ErrorCode::kDownloadInvalidMetadataSize, error);
892 }
893 
TEST_F(DeltaPerformerTest,BrilloMetadataSignatureSizeNOKTest)894 TEST_F(DeltaPerformerTest, BrilloMetadataSignatureSizeNOKTest) {
895   unsigned int seed = time(nullptr);
896   EXPECT_TRUE(performer_.Write(kDeltaMagic, sizeof(kDeltaMagic)));
897 
898   uint64_t major_version = htobe64(kBrilloMajorPayloadVersion);
899   EXPECT_TRUE(
900       performer_.Write(&major_version, PayloadMetadata::kDeltaVersionSize));
901 
902   uint64_t manifest_size = rand_r(&seed) % 256;
903   // Subtract from UINT32_MAX to avoid wrap around.
904   uint32_t metadata_signature_size = UINT32_MAX - 600;
905 
906   // The payload size is greater than |manifest_size| but smaller than
907   // |metadata_signature_size|
908   payload_.size = manifest_size + 1;
909 
910   uint64_t manifest_size_be = htobe64(manifest_size);
911   EXPECT_TRUE(performer_.Write(&manifest_size_be,
912                                PayloadMetadata::kDeltaManifestSizeSize));
913 
914   uint32_t metadata_signature_size_be = htobe32(metadata_signature_size);
915   ErrorCode error{};
916   EXPECT_FALSE(
917       performer_.Write(&metadata_signature_size_be,
918                        PayloadMetadata::kDeltaMetadataSignatureSizeSize + 1,
919                        &error));
920 
921   EXPECT_EQ(ErrorCode::kDownloadInvalidMetadataSize, error);
922 }
923 
TEST_F(DeltaPerformerTest,BrilloParsePayloadMetadataTest)924 TEST_F(DeltaPerformerTest, BrilloParsePayloadMetadataTest) {
925   brillo::Blob payload_data = GeneratePayload(
926       {}, {}, true, kBrilloMajorPayloadVersion, kSourceMinorPayloadVersion);
927   install_plan_.hash_checks_mandatory = true;
928   payload_.size = payload_data.size();
929   ErrorCode error{};
930   EXPECT_EQ(MetadataParseResult::kSuccess,
931             performer_.ParsePayloadMetadata(payload_data, &error));
932   EXPECT_EQ(ErrorCode::kSuccess, error);
933 }
934 
TEST_F(DeltaPerformerTest,BadDeltaMagicTest)935 TEST_F(DeltaPerformerTest, BadDeltaMagicTest) {
936   EXPECT_TRUE(performer_.Write("junk", 4));
937   EXPECT_FALSE(performer_.Write("morejunk", 8));
938   EXPECT_LT(performer_.Close(), 0);
939 }
940 
TEST_F(DeltaPerformerTest,MissingMandatoryMetadataSizeTest)941 TEST_F(DeltaPerformerTest, MissingMandatoryMetadataSizeTest) {
942   DoMetadataSizeTest(0, 75456, true);
943 }
944 
TEST_F(DeltaPerformerTest,MissingNonMandatoryMetadataSizeTest)945 TEST_F(DeltaPerformerTest, MissingNonMandatoryMetadataSizeTest) {
946   DoMetadataSizeTest(0, 123456, false);
947 }
948 
TEST_F(DeltaPerformerTest,InvalidMandatoryMetadataSizeTest)949 TEST_F(DeltaPerformerTest, InvalidMandatoryMetadataSizeTest) {
950   DoMetadataSizeTest(13000, 140000, true);
951 }
952 
TEST_F(DeltaPerformerTest,InvalidNonMandatoryMetadataSizeTest)953 TEST_F(DeltaPerformerTest, InvalidNonMandatoryMetadataSizeTest) {
954   DoMetadataSizeTest(40000, 50000, false);
955 }
956 
TEST_F(DeltaPerformerTest,ValidMandatoryMetadataSizeTest)957 TEST_F(DeltaPerformerTest, ValidMandatoryMetadataSizeTest) {
958   DoMetadataSizeTest(85376, 85376, true);
959 }
960 
TEST_F(DeltaPerformerTest,MandatoryEmptyMetadataSignatureTest)961 TEST_F(DeltaPerformerTest, MandatoryEmptyMetadataSignatureTest) {
962   DoMetadataSignatureTest(kEmptyMetadataSignature, true, true);
963 }
964 
TEST_F(DeltaPerformerTest,NonMandatoryEmptyMetadataSignatureTest)965 TEST_F(DeltaPerformerTest, NonMandatoryEmptyMetadataSignatureTest) {
966   DoMetadataSignatureTest(kEmptyMetadataSignature, true, false);
967 }
968 
TEST_F(DeltaPerformerTest,MandatoryInvalidMetadataSignatureTest)969 TEST_F(DeltaPerformerTest, MandatoryInvalidMetadataSignatureTest) {
970   DoMetadataSignatureTest(kInvalidMetadataSignature, true, true);
971 }
972 
TEST_F(DeltaPerformerTest,NonMandatoryInvalidMetadataSignatureTest)973 TEST_F(DeltaPerformerTest, NonMandatoryInvalidMetadataSignatureTest) {
974   DoMetadataSignatureTest(kInvalidMetadataSignature, true, false);
975 }
976 
TEST_F(DeltaPerformerTest,MandatoryValidMetadataSignature1Test)977 TEST_F(DeltaPerformerTest, MandatoryValidMetadataSignature1Test) {
978   DoMetadataSignatureTest(kValidMetadataSignature, false, true);
979 }
980 
TEST_F(DeltaPerformerTest,MandatoryValidMetadataSignature2Test)981 TEST_F(DeltaPerformerTest, MandatoryValidMetadataSignature2Test) {
982   DoMetadataSignatureTest(kValidMetadataSignature, true, true);
983 }
984 
TEST_F(DeltaPerformerTest,NonMandatoryValidMetadataSignatureTest)985 TEST_F(DeltaPerformerTest, NonMandatoryValidMetadataSignatureTest) {
986   DoMetadataSignatureTest(kValidMetadataSignature, true, false);
987 }
988 
TEST_F(DeltaPerformerTest,UsePublicKeyFromResponse)989 TEST_F(DeltaPerformerTest, UsePublicKeyFromResponse) {
990   // The result of the GetPublicKeyResponse() method is based on three things
991   //
992   //  1. Whether it's an official build; and
993   //  2. Whether the Public RSA key to be used is in the root filesystem; and
994   //  3. Whether the response has a public key
995   //
996   // We test all eight combinations to ensure that we only use the
997   // public key in the response if
998   //
999   //  a. it's not an official build; and
1000   //  b. there is no key in the root filesystem.
1001 
1002   base::ScopedTempDir temp_dir;
1003   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
1004   string non_existing_file = temp_dir.GetPath().Append("non-existing").value();
1005   string existing_file = temp_dir.GetPath().Append("existing").value();
1006   constexpr char kExistingKey[] = "Existing";
1007   ASSERT_TRUE(test_utils::WriteFileString(existing_file, kExistingKey));
1008 
1009   // Non-official build, non-existing public-key, key in response ->
1010   // kResponseKey
1011   fake_hardware_.SetIsOfficialBuild(false);
1012   performer_.public_key_path_ = non_existing_file;
1013   // This is the result of 'echo -n "Response" | base64' and is not meant to be
1014   // a valid public key, but it is valid base-64.
1015   constexpr char kResponseKey[] = "Response";
1016   constexpr char kBase64ResponseKey[] = "UmVzcG9uc2U=";
1017   install_plan_.public_key_rsa = kBase64ResponseKey;
1018   string public_key;
1019   EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1020   EXPECT_EQ(public_key, kResponseKey);
1021   // Same with official build -> no key
1022   fake_hardware_.SetIsOfficialBuild(true);
1023   EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1024   EXPECT_TRUE(public_key.empty());
1025 
1026   // Non-official build, existing public-key, key in response -> kExistingKey
1027   fake_hardware_.SetIsOfficialBuild(false);
1028   performer_.public_key_path_ = existing_file;
1029   install_plan_.public_key_rsa = kBase64ResponseKey;
1030   EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1031   EXPECT_EQ(public_key, kExistingKey);
1032   // Same with official build -> kExistingKey
1033   fake_hardware_.SetIsOfficialBuild(true);
1034   EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1035   EXPECT_EQ(public_key, kExistingKey);
1036 
1037   // Non-official build, non-existing public-key, no key in response -> no key
1038   fake_hardware_.SetIsOfficialBuild(false);
1039   performer_.public_key_path_ = non_existing_file;
1040   install_plan_.public_key_rsa = "";
1041   EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1042   EXPECT_TRUE(public_key.empty());
1043   // Same with official build -> no key
1044   fake_hardware_.SetIsOfficialBuild(true);
1045   EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1046   EXPECT_TRUE(public_key.empty());
1047 
1048   // Non-official build, existing public-key, no key in response -> kExistingKey
1049   fake_hardware_.SetIsOfficialBuild(false);
1050   performer_.public_key_path_ = existing_file;
1051   install_plan_.public_key_rsa = "";
1052   EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1053   EXPECT_EQ(public_key, kExistingKey);
1054   // Same with official build -> kExistingKey
1055   fake_hardware_.SetIsOfficialBuild(true);
1056   EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1057   EXPECT_EQ(public_key, kExistingKey);
1058 
1059   // Non-official build, non-existing public-key, key in response
1060   // but invalid base64 -> false
1061   fake_hardware_.SetIsOfficialBuild(false);
1062   performer_.public_key_path_ = non_existing_file;
1063   install_plan_.public_key_rsa = "not-valid-base64";
1064   EXPECT_FALSE(performer_.GetPublicKey(&public_key));
1065 }
1066 
1067 // TODO(197361113) re-enable the test after we bump the version in config.
TEST(DISABLED_ConfVersionTest,ConfVersionsMatch)1068 TEST(DISABLED_ConfVersionTest, ConfVersionsMatch) {
1069   // Test that the versions in update_engine.conf that is installed to the
1070   // image match the maximum supported delta versions in the update engine.
1071   uint32_t minor_version{};
1072   brillo::KeyValueStore store;
1073   EXPECT_TRUE(store.Load(GetBuildArtifactsPath().Append("update_engine.conf")));
1074   EXPECT_TRUE(utils::GetMinorVersion(store, &minor_version));
1075   EXPECT_EQ(kMaxSupportedMinorPayloadVersion, minor_version);
1076 
1077   string major_version_str;
1078   uint64_t major_version{};
1079   EXPECT_TRUE(store.GetString("PAYLOAD_MAJOR_VERSION", &major_version_str));
1080   EXPECT_TRUE(
1081       android::base::ParseUint<uint64_t>(major_version_str, &major_version));
1082   EXPECT_EQ(kMaxSupportedMajorPayloadVersion, major_version);
1083 }
1084 
TEST_F(DeltaPerformerTest,FullPayloadCanResumeTest)1085 TEST_F(DeltaPerformerTest, FullPayloadCanResumeTest) {
1086   payload_.type = InstallPayloadType::kFull;
1087   brillo::Blob expected_data =
1088       brillo::Blob(std::begin(kRandomString), std::end(kRandomString));
1089   expected_data.resize(4096);  // block size
1090   vector<AnnotatedOperation> aops;
1091   AnnotatedOperation aop;
1092   *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
1093   aop.op.set_data_offset(0);
1094   aop.op.set_data_length(expected_data.size());
1095   aop.op.set_type(InstallOperation::REPLACE);
1096   aops.push_back(aop);
1097 
1098   brillo::Blob payload_data = GeneratePayload(expected_data,
1099                                               aops,
1100                                               false,
1101                                               kBrilloMajorPayloadVersion,
1102                                               kFullPayloadMinorVersion);
1103 
1104   ASSERT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true));
1105   performer_.CheckpointUpdateProgress(true);
1106   const std::string payload_id = "12345";
1107   prefs_.SetString(kPrefsUpdateCheckResponseHash, payload_id);
1108   ASSERT_TRUE(DeltaPerformer::CanResumeUpdate(&prefs_, payload_id));
1109 }
1110 
1111 class TestDeltaPerformer : public DeltaPerformer {
1112  public:
1113   using DeltaPerformer::DeltaPerformer;
1114 
CreatePartitionWriter(const PartitionUpdate & partition_update,const InstallPlan::Partition & install_part,DynamicPartitionControlInterface * dynamic_control,size_t block_size,bool is_interactive,bool is_dynamic_partition)1115   std::unique_ptr<PartitionWriterInterface> CreatePartitionWriter(
1116       const PartitionUpdate& partition_update,
1117       const InstallPlan::Partition& install_part,
1118       DynamicPartitionControlInterface* dynamic_control,
1119       size_t block_size,
1120       bool is_interactive,
1121       bool is_dynamic_partition) {
1122     LOG(INFO) << __FUNCTION__ << ": " << install_part.name;
1123     auto node = partition_writers_.extract(install_part.name);
1124     return std::move(node.mapped());
1125   }
1126 
ShouldCheckpoint()1127   bool ShouldCheckpoint() override { return true; }
1128 
1129   std::map<std::string, std::unique_ptr<MockPartitionWriter>>
1130       partition_writers_;
1131 };
1132 
1133 namespace {
GetSourceCopyOp(uint32_t src_block,uint32_t dst_block,const void * data,size_t length)1134 AnnotatedOperation GetSourceCopyOp(uint32_t src_block,
1135                                    uint32_t dst_block,
1136                                    const void* data,
1137                                    size_t length) {
1138   AnnotatedOperation aop;
1139   *(aop.op.add_src_extents()) = ExtentForRange(0, 1);
1140   *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
1141   aop.op.set_type(InstallOperation::SOURCE_COPY);
1142   brillo::Blob src_hash;
1143   HashCalculator::RawHashOfBytes(data, length, &src_hash);
1144   aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
1145   return aop;
1146 }
1147 }  // namespace
1148 
TEST_F(DeltaPerformerTest,SetNextOpIndex)1149 TEST_F(DeltaPerformerTest, SetNextOpIndex) {
1150   TestDeltaPerformer delta_performer{&prefs_,
1151                                      &fake_boot_control_,
1152                                      &fake_hardware_,
1153                                      &mock_delegate_,
1154                                      &install_plan_,
1155                                      &payload_,
1156                                      false};
1157   brillo::Blob expected_data(std::begin(kRandomString),
1158                              std::end(kRandomString));
1159   expected_data.resize(4096 * 2);  // block size
1160   AnnotatedOperation aop;
1161 
1162   ScopedTempFile source("Source-XXXXXX");
1163   EXPECT_TRUE(test_utils::WriteFileVector(source.path(), expected_data));
1164 
1165   PartitionConfig old_part(kPartitionNameRoot);
1166   old_part.path = source.path();
1167   old_part.size = expected_data.size();
1168 
1169   delta_performer.partition_writers_[kPartitionNameRoot] =
1170       std::make_unique<MockPartitionWriter>();
1171   auto& writer1 = *delta_performer.partition_writers_[kPartitionNameRoot];
1172 
1173   Sequence seq;
1174   std::vector<size_t> indices;
1175   EXPECT_CALL(writer1, CheckpointUpdateProgress(_))
1176       .WillRepeatedly(
1177           [&indices](size_t index) mutable { indices.emplace_back(index); });
1178   EXPECT_CALL(writer1, Init(_, true, _)).Times(1).WillOnce(Return(true));
1179   EXPECT_CALL(writer1, PerformSourceCopyOperation(_, _))
1180       .Times(2)
1181       .WillRepeatedly(Return(true));
1182 
1183   brillo::Blob payload_data = GeneratePayload(
1184       brillo::Blob(),
1185       {GetSourceCopyOp(0, 0, expected_data.data(), 4096),
1186        GetSourceCopyOp(1, 1, expected_data.data() + 4096, 4096)},
1187       false,
1188       &old_part);
1189 
1190   ApplyPayloadToData(&delta_performer, payload_data, source.path(), {}, true);
1191   ASSERT_TRUE(std::is_sorted(indices.begin(), indices.end()));
1192   ASSERT_GT(indices.size(), 0UL);
1193 
1194   // Should be equal to number of operations
1195   ASSERT_EQ(indices[indices.size() - 1], 2UL);
1196 }
1197 
1198 }  // namespace chromeos_update_engine
1199