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