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