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 performer_.set_update_certificates_path("");
163 // Set the public key corresponding to the unittest private key.
164 string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath);
165 EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
166 performer_.set_public_key_path(public_key_path);
167 }
168
169 // Test helper placed where it can easily be friended from DeltaPerformer.
RunManifestValidation(const DeltaArchiveManifest & manifest,uint64_t major_version,InstallPayloadType payload_type,ErrorCode expected)170 void RunManifestValidation(const DeltaArchiveManifest& manifest,
171 uint64_t major_version,
172 InstallPayloadType payload_type,
173 ErrorCode expected) {
174 payload_.type = payload_type;
175
176 // The Manifest we are validating.
177 performer_.manifest_.CopyFrom(manifest);
178 performer_.major_payload_version_ = major_version;
179
180 EXPECT_EQ(expected, performer_.ValidateManifest());
181 }
182
GeneratePayload(const brillo::Blob & blob_data,const vector<AnnotatedOperation> & aops,bool sign_payload,PartitionConfig * old_part=nullptr)183 brillo::Blob GeneratePayload(const brillo::Blob& blob_data,
184 const vector<AnnotatedOperation>& aops,
185 bool sign_payload,
186 PartitionConfig* old_part = nullptr) {
187 return GeneratePayload(blob_data,
188 aops,
189 sign_payload,
190 kMaxSupportedMajorPayloadVersion,
191 kMaxSupportedMinorPayloadVersion,
192 old_part);
193 }
194
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)195 brillo::Blob GeneratePayload(const brillo::Blob& blob_data,
196 const vector<AnnotatedOperation>& aops,
197 bool sign_payload,
198 uint64_t major_version,
199 uint32_t minor_version,
200 PartitionConfig* old_part = nullptr) {
201 test_utils::ScopedTempFile blob_file("Blob-XXXXXX");
202 EXPECT_TRUE(test_utils::WriteFileVector(blob_file.path(), blob_data));
203
204 PayloadGenerationConfig config;
205 config.version.major = major_version;
206 config.version.minor = minor_version;
207
208 PayloadFile payload;
209 EXPECT_TRUE(payload.Init(config));
210
211 std::unique_ptr<PartitionConfig> old_part_uptr;
212 if (!old_part) {
213 old_part_uptr = std::make_unique<PartitionConfig>(kPartitionNameRoot);
214 old_part = old_part_uptr.get();
215 }
216 if (minor_version != kFullPayloadMinorVersion) {
217 // When generating a delta payload we need to include the old partition
218 // information to mark it as a delta payload.
219 if (old_part->path.empty()) {
220 old_part->path = "/dev/null";
221 }
222 }
223 PartitionConfig new_part(kPartitionNameRoot);
224 new_part.path = "/dev/zero";
225 new_part.size = 1234;
226
227 payload.AddPartition(*old_part, new_part, aops);
228
229 // We include a kernel partition without operations.
230 old_part->name = kPartitionNameKernel;
231 new_part.name = kPartitionNameKernel;
232 new_part.size = 0;
233 payload.AddPartition(*old_part, new_part, {});
234
235 test_utils::ScopedTempFile payload_file("Payload-XXXXXX");
236 string private_key =
237 sign_payload ? GetBuildArtifactsPath(kUnittestPrivateKeyPath) : "";
238 EXPECT_TRUE(payload.WritePayload(payload_file.path(),
239 blob_file.path(),
240 private_key,
241 &payload_.metadata_size));
242
243 brillo::Blob payload_data;
244 EXPECT_TRUE(utils::ReadFile(payload_file.path(), &payload_data));
245 return payload_data;
246 }
247
GenerateSourceCopyPayload(const brillo::Blob & copied_data,bool add_hash,PartitionConfig * old_part=nullptr)248 brillo::Blob GenerateSourceCopyPayload(const brillo::Blob& copied_data,
249 bool add_hash,
250 PartitionConfig* old_part = nullptr) {
251 PayloadGenerationConfig config;
252 const uint64_t kDefaultBlockSize = config.block_size;
253 EXPECT_EQ(0U, copied_data.size() % kDefaultBlockSize);
254 uint64_t num_blocks = copied_data.size() / kDefaultBlockSize;
255 AnnotatedOperation aop;
256 *(aop.op.add_src_extents()) = ExtentForRange(0, num_blocks);
257 *(aop.op.add_dst_extents()) = ExtentForRange(0, num_blocks);
258 aop.op.set_type(InstallOperation::SOURCE_COPY);
259 brillo::Blob src_hash;
260 EXPECT_TRUE(HashCalculator::RawHashOfData(copied_data, &src_hash));
261 if (add_hash)
262 aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
263
264 return GeneratePayload(brillo::Blob(), {aop}, false, old_part);
265 }
266
267 // Apply |payload_data| on partition specified in |source_path|.
268 // Expect result of performer_.Write() to be |expect_success|.
269 // Returns the result of the payload application.
ApplyPayload(const brillo::Blob & payload_data,const string & source_path,bool expect_success)270 brillo::Blob ApplyPayload(const brillo::Blob& payload_data,
271 const string& source_path,
272 bool expect_success) {
273 return ApplyPayloadToData(
274 payload_data, source_path, brillo::Blob(), expect_success);
275 }
276
277 // Apply the payload provided in |payload_data| reading from the |source_path|
278 // file and writing the contents to a new partition. The existing data in the
279 // new target file are set to |target_data| before applying the payload.
280 // Expect result of performer_.Write() to be |expect_success|.
281 // 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)282 brillo::Blob ApplyPayloadToData(const brillo::Blob& payload_data,
283 const string& source_path,
284 const brillo::Blob& target_data,
285 bool expect_success) {
286 test_utils::ScopedTempFile new_part("Partition-XXXXXX");
287 EXPECT_TRUE(test_utils::WriteFileVector(new_part.path(), target_data));
288
289 // We installed the operations only in the rootfs partition, but the
290 // delta performer needs to access all the partitions.
291 fake_boot_control_.SetPartitionDevice(
292 kPartitionNameRoot, install_plan_.target_slot, new_part.path());
293 fake_boot_control_.SetPartitionDevice(
294 kPartitionNameRoot, install_plan_.source_slot, source_path);
295 fake_boot_control_.SetPartitionDevice(
296 kPartitionNameKernel, install_plan_.target_slot, "/dev/null");
297 fake_boot_control_.SetPartitionDevice(
298 kPartitionNameKernel, install_plan_.source_slot, "/dev/null");
299
300 EXPECT_EQ(expect_success,
301 performer_.Write(payload_data.data(), payload_data.size()));
302 EXPECT_EQ(0, performer_.Close());
303
304 brillo::Blob partition_data;
305 EXPECT_TRUE(utils::ReadFile(new_part.path(), &partition_data));
306 return partition_data;
307 }
308
309 // Calls delta performer's Write method by pretending to pass in bytes from a
310 // delta file whose metadata size is actual_metadata_size and tests if all
311 // checks are correctly performed if the install plan contains
312 // expected_metadata_size and that the result of the parsing are as per
313 // hash_checks_mandatory flag.
DoMetadataSizeTest(uint64_t expected_metadata_size,uint64_t actual_metadata_size,bool hash_checks_mandatory)314 void DoMetadataSizeTest(uint64_t expected_metadata_size,
315 uint64_t actual_metadata_size,
316 bool hash_checks_mandatory) {
317 install_plan_.hash_checks_mandatory = hash_checks_mandatory;
318
319 // Set a valid magic string and version number 1.
320 EXPECT_TRUE(performer_.Write("CrAU", 4));
321 uint64_t version = htobe64(kChromeOSMajorPayloadVersion);
322 EXPECT_TRUE(performer_.Write(&version, 8));
323
324 payload_.metadata_size = expected_metadata_size;
325 ErrorCode error_code;
326 // When filling in size in manifest, exclude the size of the 20-byte header.
327 uint64_t size_in_manifest = htobe64(actual_metadata_size - 20);
328 bool result = performer_.Write(&size_in_manifest, 8, &error_code);
329 if (expected_metadata_size == actual_metadata_size ||
330 !hash_checks_mandatory) {
331 EXPECT_TRUE(result);
332 } else {
333 EXPECT_FALSE(result);
334 EXPECT_EQ(ErrorCode::kDownloadInvalidMetadataSize, error_code);
335 }
336
337 EXPECT_LT(performer_.Close(), 0);
338 }
339
340 // Generates a valid delta file but tests the delta performer by suppling
341 // different metadata signatures as per metadata_signature_test flag and
342 // 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)343 void DoMetadataSignatureTest(MetadataSignatureTest metadata_signature_test,
344 bool sign_payload,
345 bool hash_checks_mandatory) {
346 // Loads the payload and parses the manifest.
347 brillo::Blob payload = GeneratePayload(brillo::Blob(),
348 vector<AnnotatedOperation>(),
349 sign_payload,
350 kChromeOSMajorPayloadVersion,
351 kFullPayloadMinorVersion);
352
353 LOG(INFO) << "Payload size: " << payload.size();
354
355 install_plan_.hash_checks_mandatory = hash_checks_mandatory;
356
357 MetadataParseResult expected_result, actual_result;
358 ErrorCode expected_error, actual_error;
359
360 // Fill up the metadata signature in install plan according to the test.
361 switch (metadata_signature_test) {
362 case kEmptyMetadataSignature:
363 payload_.metadata_signature.clear();
364 expected_result = MetadataParseResult::kError;
365 expected_error = ErrorCode::kDownloadMetadataSignatureMissingError;
366 break;
367
368 case kInvalidMetadataSignature:
369 payload_.metadata_signature = kBogusMetadataSignature1;
370 expected_result = MetadataParseResult::kError;
371 expected_error = ErrorCode::kDownloadMetadataSignatureMismatch;
372 break;
373
374 case kValidMetadataSignature:
375 default:
376 // Set the install plan's metadata size to be the same as the one
377 // in the manifest so that we pass the metadata size checks. Only
378 // then we can get to manifest signature checks.
379 ASSERT_TRUE(PayloadSigner::GetMetadataSignature(
380 payload.data(),
381 payload_.metadata_size,
382 GetBuildArtifactsPath(kUnittestPrivateKeyPath),
383 &payload_.metadata_signature));
384 EXPECT_FALSE(payload_.metadata_signature.empty());
385 expected_result = MetadataParseResult::kSuccess;
386 expected_error = ErrorCode::kSuccess;
387 break;
388 }
389
390 // Ignore the expected result/error if hash checks are not mandatory.
391 if (!hash_checks_mandatory) {
392 expected_result = MetadataParseResult::kSuccess;
393 expected_error = ErrorCode::kSuccess;
394 }
395
396 // Init actual_error with an invalid value so that we make sure
397 // ParsePayloadMetadata properly populates it in all cases.
398 actual_error = ErrorCode::kUmaReportedMax;
399 actual_result = performer_.ParsePayloadMetadata(payload, &actual_error);
400
401 EXPECT_EQ(expected_result, actual_result);
402 EXPECT_EQ(expected_error, actual_error);
403
404 // Check that the parsed metadata size is what's expected. This test
405 // implicitly confirms that the metadata signature is valid, if required.
406 EXPECT_EQ(payload_.metadata_size, performer_.metadata_size_);
407 }
408
409 // Helper function to pretend that the ECC file descriptor was already opened.
410 // Returns a pointer to the created file descriptor.
SetFakeECCFile(size_t size)411 FakeFileDescriptor* SetFakeECCFile(size_t size) {
412 EXPECT_FALSE(performer_.source_ecc_fd_) << "source_ecc_fd_ already open.";
413 FakeFileDescriptor* ret = new FakeFileDescriptor();
414 fake_ecc_fd_.reset(ret);
415 // Call open to simulate it was already opened.
416 ret->Open("", 0);
417 ret->SetFileSize(size);
418 performer_.source_ecc_fd_ = fake_ecc_fd_;
419 return ret;
420 }
421
GetSourceEccRecoveredFailures() const422 uint64_t GetSourceEccRecoveredFailures() const {
423 return performer_.source_ecc_recovered_failures_;
424 }
425
426 FakePrefs prefs_;
427 InstallPlan install_plan_;
428 InstallPlan::Payload payload_;
429 FakeBootControl fake_boot_control_;
430 FakeHardware fake_hardware_;
431 MockDownloadActionDelegate mock_delegate_;
432 FileDescriptorPtr fake_ecc_fd_;
433 DeltaPerformer performer_{&prefs_,
434 &fake_boot_control_,
435 &fake_hardware_,
436 &mock_delegate_,
437 &install_plan_,
438 &payload_,
439 false /* interactive*/};
440 };
441
TEST_F(DeltaPerformerTest,FullPayloadWriteTest)442 TEST_F(DeltaPerformerTest, FullPayloadWriteTest) {
443 payload_.type = InstallPayloadType::kFull;
444 brillo::Blob expected_data =
445 brillo::Blob(std::begin(kRandomString), std::end(kRandomString));
446 expected_data.resize(4096); // block size
447 vector<AnnotatedOperation> aops;
448 AnnotatedOperation aop;
449 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
450 aop.op.set_data_offset(0);
451 aop.op.set_data_length(expected_data.size());
452 aop.op.set_type(InstallOperation::REPLACE);
453 aops.push_back(aop);
454
455 brillo::Blob payload_data = GeneratePayload(expected_data,
456 aops,
457 false,
458 kChromeOSMajorPayloadVersion,
459 kFullPayloadMinorVersion);
460
461 EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true));
462 }
463
TEST_F(DeltaPerformerTest,ShouldCancelTest)464 TEST_F(DeltaPerformerTest, ShouldCancelTest) {
465 payload_.type = InstallPayloadType::kFull;
466 brillo::Blob expected_data =
467 brillo::Blob(std::begin(kRandomString), std::end(kRandomString));
468 expected_data.resize(4096); // block size
469 vector<AnnotatedOperation> aops;
470 AnnotatedOperation aop;
471 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
472 aop.op.set_data_offset(0);
473 aop.op.set_data_length(expected_data.size());
474 aop.op.set_type(InstallOperation::REPLACE);
475 aops.push_back(aop);
476
477 brillo::Blob payload_data = GeneratePayload(expected_data,
478 aops,
479 false,
480 kChromeOSMajorPayloadVersion,
481 kFullPayloadMinorVersion);
482
483 testing::Mock::VerifyAndClearExpectations(&mock_delegate_);
484 EXPECT_CALL(mock_delegate_, ShouldCancel(_))
485 .WillOnce(testing::DoAll(testing::SetArgPointee<0>(ErrorCode::kError),
486 testing::Return(true)));
487
488 ApplyPayload(payload_data, "/dev/null", false);
489 }
490
TEST_F(DeltaPerformerTest,ReplaceOperationTest)491 TEST_F(DeltaPerformerTest, ReplaceOperationTest) {
492 brillo::Blob expected_data =
493 brillo::Blob(std::begin(kRandomString), std::end(kRandomString));
494 expected_data.resize(4096); // block size
495 vector<AnnotatedOperation> aops;
496 AnnotatedOperation aop;
497 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
498 aop.op.set_data_offset(0);
499 aop.op.set_data_length(expected_data.size());
500 aop.op.set_type(InstallOperation::REPLACE);
501 aops.push_back(aop);
502
503 brillo::Blob payload_data = GeneratePayload(expected_data, aops, false);
504
505 EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true));
506 }
507
TEST_F(DeltaPerformerTest,ReplaceBzOperationTest)508 TEST_F(DeltaPerformerTest, ReplaceBzOperationTest) {
509 brillo::Blob expected_data =
510 brillo::Blob(std::begin(kRandomString), std::end(kRandomString));
511 expected_data.resize(4096); // block size
512 brillo::Blob bz_data;
513 EXPECT_TRUE(BzipCompress(expected_data, &bz_data));
514
515 vector<AnnotatedOperation> aops;
516 AnnotatedOperation aop;
517 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
518 aop.op.set_data_offset(0);
519 aop.op.set_data_length(bz_data.size());
520 aop.op.set_type(InstallOperation::REPLACE_BZ);
521 aops.push_back(aop);
522
523 brillo::Blob payload_data = GeneratePayload(bz_data, aops, false);
524
525 EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true));
526 }
527
TEST_F(DeltaPerformerTest,ReplaceXzOperationTest)528 TEST_F(DeltaPerformerTest, ReplaceXzOperationTest) {
529 brillo::Blob xz_data(std::begin(kXzCompressedData),
530 std::end(kXzCompressedData));
531 // The compressed xz data contains a single "a" and padded with zero for the
532 // rest of the block.
533 brillo::Blob expected_data = brillo::Blob(4096, 0);
534 expected_data[0] = 'a';
535
536 AnnotatedOperation aop;
537 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
538 aop.op.set_data_offset(0);
539 aop.op.set_data_length(xz_data.size());
540 aop.op.set_type(InstallOperation::REPLACE_XZ);
541 vector<AnnotatedOperation> aops = {aop};
542
543 brillo::Blob payload_data = GeneratePayload(xz_data, aops, false);
544
545 EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null", true));
546 }
547
TEST_F(DeltaPerformerTest,ZeroOperationTest)548 TEST_F(DeltaPerformerTest, ZeroOperationTest) {
549 brillo::Blob existing_data = brillo::Blob(4096 * 10, 'a');
550 brillo::Blob expected_data = existing_data;
551 // Blocks 4, 5 and 7 should have zeros instead of 'a' after the operation is
552 // applied.
553 std::fill(
554 expected_data.data() + 4096 * 4, expected_data.data() + 4096 * 6, 0);
555 std::fill(
556 expected_data.data() + 4096 * 7, expected_data.data() + 4096 * 8, 0);
557
558 AnnotatedOperation aop;
559 *(aop.op.add_dst_extents()) = ExtentForRange(4, 2);
560 *(aop.op.add_dst_extents()) = ExtentForRange(7, 1);
561 aop.op.set_type(InstallOperation::ZERO);
562 vector<AnnotatedOperation> aops = {aop};
563
564 brillo::Blob payload_data = GeneratePayload(brillo::Blob(), aops, false);
565
566 EXPECT_EQ(expected_data,
567 ApplyPayloadToData(payload_data, "/dev/null", existing_data, true));
568 }
569
TEST_F(DeltaPerformerTest,SourceCopyOperationTest)570 TEST_F(DeltaPerformerTest, SourceCopyOperationTest) {
571 brillo::Blob expected_data(std::begin(kRandomString),
572 std::end(kRandomString));
573 expected_data.resize(4096); // block size
574 AnnotatedOperation aop;
575 *(aop.op.add_src_extents()) = ExtentForRange(0, 1);
576 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
577 aop.op.set_type(InstallOperation::SOURCE_COPY);
578 brillo::Blob src_hash;
579 EXPECT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash));
580 aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
581
582 test_utils::ScopedTempFile source("Source-XXXXXX");
583 EXPECT_TRUE(test_utils::WriteFileVector(source.path(), expected_data));
584
585 PartitionConfig old_part(kPartitionNameRoot);
586 old_part.path = source.path();
587 old_part.size = expected_data.size();
588
589 brillo::Blob payload_data =
590 GeneratePayload(brillo::Blob(), {aop}, false, &old_part);
591
592 EXPECT_EQ(expected_data, ApplyPayload(payload_data, source.path(), true));
593 }
594
TEST_F(DeltaPerformerTest,PuffdiffOperationTest)595 TEST_F(DeltaPerformerTest, PuffdiffOperationTest) {
596 AnnotatedOperation aop;
597 *(aop.op.add_src_extents()) = ExtentForRange(0, 1);
598 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
599 brillo::Blob puffdiff_payload(std::begin(puffdiff_patch),
600 std::end(puffdiff_patch));
601 aop.op.set_data_offset(0);
602 aop.op.set_data_length(puffdiff_payload.size());
603 aop.op.set_type(InstallOperation::PUFFDIFF);
604 brillo::Blob src(std::begin(src_deflates), std::end(src_deflates));
605 src.resize(4096); // block size
606 brillo::Blob src_hash;
607 EXPECT_TRUE(HashCalculator::RawHashOfData(src, &src_hash));
608 aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
609
610 test_utils::ScopedTempFile source("Source-XXXXXX");
611 EXPECT_TRUE(test_utils::WriteFileVector(source.path(), src));
612
613 PartitionConfig old_part(kPartitionNameRoot);
614 old_part.path = source.path();
615 old_part.size = src.size();
616
617 brillo::Blob payload_data =
618 GeneratePayload(puffdiff_payload, {aop}, false, &old_part);
619
620 brillo::Blob dst(std::begin(dst_deflates), std::end(dst_deflates));
621 EXPECT_EQ(dst, ApplyPayload(payload_data, source.path(), true));
622 }
623
TEST_F(DeltaPerformerTest,SourceHashMismatchTest)624 TEST_F(DeltaPerformerTest, SourceHashMismatchTest) {
625 brillo::Blob expected_data = {'f', 'o', 'o'};
626 brillo::Blob actual_data = {'b', 'a', 'r'};
627 expected_data.resize(4096); // block size
628 actual_data.resize(4096); // block size
629
630 AnnotatedOperation aop;
631 *(aop.op.add_src_extents()) = ExtentForRange(0, 1);
632 *(aop.op.add_dst_extents()) = ExtentForRange(0, 1);
633 aop.op.set_type(InstallOperation::SOURCE_COPY);
634 brillo::Blob src_hash;
635 EXPECT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash));
636 aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
637
638 test_utils::ScopedTempFile source("Source-XXXXXX");
639 EXPECT_TRUE(test_utils::WriteFileVector(source.path(), actual_data));
640
641 PartitionConfig old_part(kPartitionNameRoot);
642 old_part.path = source.path();
643 old_part.size = actual_data.size();
644
645 brillo::Blob payload_data =
646 GeneratePayload(brillo::Blob(), {aop}, false, &old_part);
647
648 EXPECT_EQ(actual_data, ApplyPayload(payload_data, source.path(), false));
649 }
650
651 // Test that the error-corrected file descriptor is used to read the partition
652 // since the source partition doesn't match the operation hash.
TEST_F(DeltaPerformerTest,ErrorCorrectionSourceCopyFallbackTest)653 TEST_F(DeltaPerformerTest, ErrorCorrectionSourceCopyFallbackTest) {
654 constexpr size_t kCopyOperationSize = 4 * 4096;
655 test_utils::ScopedTempFile source("Source-XXXXXX");
656 // Write invalid data to the source image, which doesn't match the expected
657 // hash.
658 brillo::Blob invalid_data(kCopyOperationSize, 0x55);
659 EXPECT_TRUE(test_utils::WriteFileVector(source.path(), invalid_data));
660
661 // Setup the fec file descriptor as the fake stream, which matches
662 // |expected_data|.
663 FakeFileDescriptor* fake_fec = SetFakeECCFile(kCopyOperationSize);
664 brillo::Blob expected_data = FakeFileDescriptorData(kCopyOperationSize);
665
666 PartitionConfig old_part(kPartitionNameRoot);
667 old_part.path = source.path();
668 old_part.size = invalid_data.size();
669
670 brillo::Blob payload_data =
671 GenerateSourceCopyPayload(expected_data, true, &old_part);
672 EXPECT_EQ(expected_data, ApplyPayload(payload_data, source.path(), true));
673 // Verify that the fake_fec was actually used.
674 EXPECT_EQ(1U, fake_fec->GetReadOps().size());
675 EXPECT_EQ(1U, GetSourceEccRecoveredFailures());
676 }
677
678 // Test that the error-corrected file descriptor is used to read a partition
679 // when no hash is available for SOURCE_COPY but it falls back to the normal
680 // file descriptor when the size of the error corrected one is too small.
TEST_F(DeltaPerformerTest,ErrorCorrectionSourceCopyWhenNoHashFallbackTest)681 TEST_F(DeltaPerformerTest, ErrorCorrectionSourceCopyWhenNoHashFallbackTest) {
682 constexpr size_t kCopyOperationSize = 4 * 4096;
683 test_utils::ScopedTempFile source("Source-XXXXXX");
684 // Setup the source path with the right expected data.
685 brillo::Blob expected_data = FakeFileDescriptorData(kCopyOperationSize);
686 EXPECT_TRUE(test_utils::WriteFileVector(source.path(), expected_data));
687
688 // Setup the fec file descriptor as the fake stream, with smaller data than
689 // the expected.
690 FakeFileDescriptor* fake_fec = SetFakeECCFile(kCopyOperationSize / 2);
691
692 PartitionConfig old_part(kPartitionNameRoot);
693 old_part.path = source.path();
694 old_part.size = expected_data.size();
695
696 // The payload operation doesn't include an operation hash.
697 brillo::Blob payload_data =
698 GenerateSourceCopyPayload(expected_data, false, &old_part);
699 EXPECT_EQ(expected_data, ApplyPayload(payload_data, source.path(), true));
700 // Verify that the fake_fec was attempted to be used. Since the file
701 // descriptor is shorter it can actually do more than one read to realize it
702 // reached the EOF.
703 EXPECT_LE(1U, fake_fec->GetReadOps().size());
704 // This fallback doesn't count as an error-corrected operation since the
705 // operation hash was not available.
706 EXPECT_EQ(0U, GetSourceEccRecoveredFailures());
707 }
708
TEST_F(DeltaPerformerTest,ChooseSourceFDTest)709 TEST_F(DeltaPerformerTest, ChooseSourceFDTest) {
710 constexpr size_t kSourceSize = 4 * 4096;
711 test_utils::ScopedTempFile source("Source-XXXXXX");
712 // Write invalid data to the source image, which doesn't match the expected
713 // hash.
714 brillo::Blob invalid_data(kSourceSize, 0x55);
715 EXPECT_TRUE(test_utils::WriteFileVector(source.path(), invalid_data));
716
717 performer_.source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
718 performer_.source_fd_->Open(source.path().c_str(), O_RDONLY);
719 performer_.block_size_ = 4096;
720
721 // Setup the fec file descriptor as the fake stream, which matches
722 // |expected_data|.
723 FakeFileDescriptor* fake_fec = SetFakeECCFile(kSourceSize);
724 brillo::Blob expected_data = FakeFileDescriptorData(kSourceSize);
725
726 InstallOperation op;
727 *(op.add_src_extents()) = ExtentForRange(0, kSourceSize / 4096);
728 brillo::Blob src_hash;
729 EXPECT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash));
730 op.set_src_sha256_hash(src_hash.data(), src_hash.size());
731
732 ErrorCode error = ErrorCode::kSuccess;
733 EXPECT_EQ(performer_.source_ecc_fd_, performer_.ChooseSourceFD(op, &error));
734 EXPECT_EQ(ErrorCode::kSuccess, error);
735 // Verify that the fake_fec was actually used.
736 EXPECT_EQ(1U, fake_fec->GetReadOps().size());
737 EXPECT_EQ(1U, GetSourceEccRecoveredFailures());
738 }
739
TEST_F(DeltaPerformerTest,ExtentsToByteStringTest)740 TEST_F(DeltaPerformerTest, ExtentsToByteStringTest) {
741 uint64_t test[] = {1, 1, 4, 2, 0, 1};
742 static_assert(arraysize(test) % 2 == 0, "Array size uneven");
743 const uint64_t block_size = 4096;
744 const uint64_t file_length = 4 * block_size - 13;
745
746 google::protobuf::RepeatedPtrField<Extent> extents;
747 for (size_t i = 0; i < arraysize(test); i += 2) {
748 *(extents.Add()) = ExtentForRange(test[i], test[i + 1]);
749 }
750
751 string expected_output = "4096:4096,16384:8192,0:4083";
752 string actual_output;
753 EXPECT_TRUE(DeltaPerformer::ExtentsToBsdiffPositionsString(
754 extents, block_size, file_length, &actual_output));
755 EXPECT_EQ(expected_output, actual_output);
756 }
757
TEST_F(DeltaPerformerTest,ValidateManifestFullGoodTest)758 TEST_F(DeltaPerformerTest, ValidateManifestFullGoodTest) {
759 // The Manifest we are validating.
760 DeltaArchiveManifest manifest;
761 manifest.mutable_new_kernel_info();
762 manifest.mutable_new_rootfs_info();
763 manifest.set_minor_version(kFullPayloadMinorVersion);
764
765 RunManifestValidation(manifest,
766 kChromeOSMajorPayloadVersion,
767 InstallPayloadType::kFull,
768 ErrorCode::kSuccess);
769 }
770
TEST_F(DeltaPerformerTest,ValidateManifestDeltaGoodTest)771 TEST_F(DeltaPerformerTest, ValidateManifestDeltaGoodTest) {
772 // The Manifest we are validating.
773 DeltaArchiveManifest manifest;
774 manifest.mutable_old_kernel_info();
775 manifest.mutable_old_rootfs_info();
776 manifest.mutable_new_kernel_info();
777 manifest.mutable_new_rootfs_info();
778 manifest.set_minor_version(kMaxSupportedMinorPayloadVersion);
779
780 RunManifestValidation(manifest,
781 kChromeOSMajorPayloadVersion,
782 InstallPayloadType::kDelta,
783 ErrorCode::kSuccess);
784 }
785
TEST_F(DeltaPerformerTest,ValidateManifestDeltaMinGoodTest)786 TEST_F(DeltaPerformerTest, ValidateManifestDeltaMinGoodTest) {
787 // The Manifest we are validating.
788 DeltaArchiveManifest manifest;
789 manifest.mutable_old_kernel_info();
790 manifest.mutable_old_rootfs_info();
791 manifest.mutable_new_kernel_info();
792 manifest.mutable_new_rootfs_info();
793 manifest.set_minor_version(kMinSupportedMinorPayloadVersion);
794
795 RunManifestValidation(manifest,
796 kChromeOSMajorPayloadVersion,
797 InstallPayloadType::kDelta,
798 ErrorCode::kSuccess);
799 }
800
TEST_F(DeltaPerformerTest,ValidateManifestFullUnsetMinorVersion)801 TEST_F(DeltaPerformerTest, ValidateManifestFullUnsetMinorVersion) {
802 // The Manifest we are validating.
803 DeltaArchiveManifest manifest;
804
805 RunManifestValidation(manifest,
806 kMaxSupportedMajorPayloadVersion,
807 InstallPayloadType::kFull,
808 ErrorCode::kSuccess);
809 }
810
TEST_F(DeltaPerformerTest,ValidateManifestDeltaUnsetMinorVersion)811 TEST_F(DeltaPerformerTest, ValidateManifestDeltaUnsetMinorVersion) {
812 // The Manifest we are validating.
813 DeltaArchiveManifest manifest;
814 // Add an empty old_rootfs_info() to trick the DeltaPerformer into think that
815 // this is a delta payload manifest with a missing minor version.
816 manifest.mutable_old_rootfs_info();
817
818 RunManifestValidation(manifest,
819 kMaxSupportedMajorPayloadVersion,
820 InstallPayloadType::kDelta,
821 ErrorCode::kUnsupportedMinorPayloadVersion);
822 }
823
TEST_F(DeltaPerformerTest,ValidateManifestFullOldKernelTest)824 TEST_F(DeltaPerformerTest, ValidateManifestFullOldKernelTest) {
825 // The Manifest we are validating.
826 DeltaArchiveManifest manifest;
827 manifest.mutable_old_kernel_info();
828 manifest.mutable_new_kernel_info();
829 manifest.mutable_new_rootfs_info();
830 manifest.set_minor_version(kMaxSupportedMinorPayloadVersion);
831
832 RunManifestValidation(manifest,
833 kChromeOSMajorPayloadVersion,
834 InstallPayloadType::kFull,
835 ErrorCode::kPayloadMismatchedType);
836 }
837
TEST_F(DeltaPerformerTest,ValidateManifestFullOldRootfsTest)838 TEST_F(DeltaPerformerTest, ValidateManifestFullOldRootfsTest) {
839 // The Manifest we are validating.
840 DeltaArchiveManifest manifest;
841 manifest.mutable_old_rootfs_info();
842 manifest.mutable_new_kernel_info();
843 manifest.mutable_new_rootfs_info();
844 manifest.set_minor_version(kMaxSupportedMinorPayloadVersion);
845
846 RunManifestValidation(manifest,
847 kChromeOSMajorPayloadVersion,
848 InstallPayloadType::kFull,
849 ErrorCode::kPayloadMismatchedType);
850 }
851
TEST_F(DeltaPerformerTest,ValidateManifestFullPartitionUpdateTest)852 TEST_F(DeltaPerformerTest, ValidateManifestFullPartitionUpdateTest) {
853 // The Manifest we are validating.
854 DeltaArchiveManifest manifest;
855 PartitionUpdate* partition = manifest.add_partitions();
856 partition->mutable_old_partition_info();
857 partition->mutable_new_partition_info();
858 manifest.set_minor_version(kMaxSupportedMinorPayloadVersion);
859
860 RunManifestValidation(manifest,
861 kBrilloMajorPayloadVersion,
862 InstallPayloadType::kFull,
863 ErrorCode::kPayloadMismatchedType);
864 }
865
TEST_F(DeltaPerformerTest,ValidateManifestBadMinorVersion)866 TEST_F(DeltaPerformerTest, ValidateManifestBadMinorVersion) {
867 // The Manifest we are validating.
868 DeltaArchiveManifest manifest;
869
870 // Generate a bad version number.
871 manifest.set_minor_version(kMaxSupportedMinorPayloadVersion + 10000);
872 // Mark the manifest as a delta payload by setting old_rootfs_info.
873 manifest.mutable_old_rootfs_info();
874
875 RunManifestValidation(manifest,
876 kMaxSupportedMajorPayloadVersion,
877 InstallPayloadType::kDelta,
878 ErrorCode::kUnsupportedMinorPayloadVersion);
879 }
880
TEST_F(DeltaPerformerTest,ValidateManifestDowngrade)881 TEST_F(DeltaPerformerTest, ValidateManifestDowngrade) {
882 // The Manifest we are validating.
883 DeltaArchiveManifest manifest;
884
885 manifest.set_minor_version(kFullPayloadMinorVersion);
886 manifest.set_max_timestamp(1);
887 fake_hardware_.SetBuildTimestamp(2);
888
889 RunManifestValidation(manifest,
890 kMaxSupportedMajorPayloadVersion,
891 InstallPayloadType::kFull,
892 ErrorCode::kPayloadTimestampError);
893 }
894
TEST_F(DeltaPerformerTest,BrilloMetadataSignatureSizeTest)895 TEST_F(DeltaPerformerTest, BrilloMetadataSignatureSizeTest) {
896 unsigned int seed = time(nullptr);
897 EXPECT_TRUE(performer_.Write(kDeltaMagic, sizeof(kDeltaMagic)));
898
899 uint64_t major_version = htobe64(kBrilloMajorPayloadVersion);
900 EXPECT_TRUE(performer_.Write(&major_version, 8));
901
902 uint64_t manifest_size = rand_r(&seed) % 256;
903 uint64_t manifest_size_be = htobe64(manifest_size);
904 EXPECT_TRUE(performer_.Write(&manifest_size_be, 8));
905
906 uint32_t metadata_signature_size = rand_r(&seed) % 256;
907 uint32_t metadata_signature_size_be = htobe32(metadata_signature_size);
908 EXPECT_TRUE(performer_.Write(&metadata_signature_size_be, 4));
909
910 EXPECT_LT(performer_.Close(), 0);
911
912 EXPECT_TRUE(performer_.IsHeaderParsed());
913 EXPECT_EQ(kBrilloMajorPayloadVersion, performer_.major_payload_version_);
914 EXPECT_EQ(24 + manifest_size, performer_.metadata_size_); // 4 + 8 + 8 + 4
915 EXPECT_EQ(metadata_signature_size, performer_.metadata_signature_size_);
916 }
917
TEST_F(DeltaPerformerTest,BrilloParsePayloadMetadataTest)918 TEST_F(DeltaPerformerTest, BrilloParsePayloadMetadataTest) {
919 brillo::Blob payload_data = GeneratePayload(
920 {}, {}, true, kBrilloMajorPayloadVersion, kSourceMinorPayloadVersion);
921 install_plan_.hash_checks_mandatory = true;
922 ErrorCode error;
923 EXPECT_EQ(MetadataParseResult::kSuccess,
924 performer_.ParsePayloadMetadata(payload_data, &error));
925 EXPECT_EQ(ErrorCode::kSuccess, error);
926 }
927
TEST_F(DeltaPerformerTest,BadDeltaMagicTest)928 TEST_F(DeltaPerformerTest, BadDeltaMagicTest) {
929 EXPECT_TRUE(performer_.Write("junk", 4));
930 EXPECT_FALSE(performer_.Write("morejunk", 8));
931 EXPECT_LT(performer_.Close(), 0);
932 }
933
TEST_F(DeltaPerformerTest,MissingMandatoryMetadataSizeTest)934 TEST_F(DeltaPerformerTest, MissingMandatoryMetadataSizeTest) {
935 DoMetadataSizeTest(0, 75456, true);
936 }
937
TEST_F(DeltaPerformerTest,MissingNonMandatoryMetadataSizeTest)938 TEST_F(DeltaPerformerTest, MissingNonMandatoryMetadataSizeTest) {
939 DoMetadataSizeTest(0, 123456, false);
940 }
941
TEST_F(DeltaPerformerTest,InvalidMandatoryMetadataSizeTest)942 TEST_F(DeltaPerformerTest, InvalidMandatoryMetadataSizeTest) {
943 DoMetadataSizeTest(13000, 140000, true);
944 }
945
TEST_F(DeltaPerformerTest,InvalidNonMandatoryMetadataSizeTest)946 TEST_F(DeltaPerformerTest, InvalidNonMandatoryMetadataSizeTest) {
947 DoMetadataSizeTest(40000, 50000, false);
948 }
949
TEST_F(DeltaPerformerTest,ValidMandatoryMetadataSizeTest)950 TEST_F(DeltaPerformerTest, ValidMandatoryMetadataSizeTest) {
951 DoMetadataSizeTest(85376, 85376, true);
952 }
953
TEST_F(DeltaPerformerTest,MandatoryEmptyMetadataSignatureTest)954 TEST_F(DeltaPerformerTest, MandatoryEmptyMetadataSignatureTest) {
955 DoMetadataSignatureTest(kEmptyMetadataSignature, true, true);
956 }
957
TEST_F(DeltaPerformerTest,NonMandatoryEmptyMetadataSignatureTest)958 TEST_F(DeltaPerformerTest, NonMandatoryEmptyMetadataSignatureTest) {
959 DoMetadataSignatureTest(kEmptyMetadataSignature, true, false);
960 }
961
TEST_F(DeltaPerformerTest,MandatoryInvalidMetadataSignatureTest)962 TEST_F(DeltaPerformerTest, MandatoryInvalidMetadataSignatureTest) {
963 DoMetadataSignatureTest(kInvalidMetadataSignature, true, true);
964 }
965
TEST_F(DeltaPerformerTest,NonMandatoryInvalidMetadataSignatureTest)966 TEST_F(DeltaPerformerTest, NonMandatoryInvalidMetadataSignatureTest) {
967 DoMetadataSignatureTest(kInvalidMetadataSignature, true, false);
968 }
969
TEST_F(DeltaPerformerTest,MandatoryValidMetadataSignature1Test)970 TEST_F(DeltaPerformerTest, MandatoryValidMetadataSignature1Test) {
971 DoMetadataSignatureTest(kValidMetadataSignature, false, true);
972 }
973
TEST_F(DeltaPerformerTest,MandatoryValidMetadataSignature2Test)974 TEST_F(DeltaPerformerTest, MandatoryValidMetadataSignature2Test) {
975 DoMetadataSignatureTest(kValidMetadataSignature, true, true);
976 }
977
TEST_F(DeltaPerformerTest,NonMandatoryValidMetadataSignatureTest)978 TEST_F(DeltaPerformerTest, NonMandatoryValidMetadataSignatureTest) {
979 DoMetadataSignatureTest(kValidMetadataSignature, true, false);
980 }
981
TEST_F(DeltaPerformerTest,UsePublicKeyFromResponse)982 TEST_F(DeltaPerformerTest, UsePublicKeyFromResponse) {
983 // The result of the GetPublicKeyResponse() method is based on three things
984 //
985 // 1. Whether it's an official build; and
986 // 2. Whether the Public RSA key to be used is in the root filesystem; and
987 // 3. Whether the response has a public key
988 //
989 // We test all eight combinations to ensure that we only use the
990 // public key in the response if
991 //
992 // a. it's not an official build; and
993 // b. there is no key in the root filesystem.
994
995 base::ScopedTempDir temp_dir;
996 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
997 string non_existing_file = temp_dir.GetPath().Append("non-existing").value();
998 string existing_file = temp_dir.GetPath().Append("existing").value();
999 constexpr char kExistingKey[] = "Existing";
1000 ASSERT_TRUE(test_utils::WriteFileString(existing_file, kExistingKey));
1001
1002 // Non-official build, non-existing public-key, key in response ->
1003 // kResponseKey
1004 fake_hardware_.SetIsOfficialBuild(false);
1005 performer_.public_key_path_ = non_existing_file;
1006 // This is the result of 'echo -n "Response" | base64' and is not meant to be
1007 // a valid public key, but it is valid base-64.
1008 constexpr char kResponseKey[] = "Response";
1009 constexpr char kBase64ResponseKey[] = "UmVzcG9uc2U=";
1010 install_plan_.public_key_rsa = kBase64ResponseKey;
1011 string public_key;
1012 EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1013 EXPECT_EQ(public_key, kResponseKey);
1014 // Same with official build -> no key
1015 fake_hardware_.SetIsOfficialBuild(true);
1016 EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1017 EXPECT_TRUE(public_key.empty());
1018
1019 // Non-official build, existing public-key, key in response -> kExistingKey
1020 fake_hardware_.SetIsOfficialBuild(false);
1021 performer_.public_key_path_ = existing_file;
1022 install_plan_.public_key_rsa = kBase64ResponseKey;
1023 EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1024 EXPECT_EQ(public_key, kExistingKey);
1025 // Same with official build -> kExistingKey
1026 fake_hardware_.SetIsOfficialBuild(true);
1027 EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1028 EXPECT_EQ(public_key, kExistingKey);
1029
1030 // Non-official build, non-existing public-key, no key in response -> no key
1031 fake_hardware_.SetIsOfficialBuild(false);
1032 performer_.public_key_path_ = non_existing_file;
1033 install_plan_.public_key_rsa = "";
1034 EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1035 EXPECT_TRUE(public_key.empty());
1036 // Same with official build -> no key
1037 fake_hardware_.SetIsOfficialBuild(true);
1038 EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1039 EXPECT_TRUE(public_key.empty());
1040
1041 // Non-official build, existing public-key, no key in response -> kExistingKey
1042 fake_hardware_.SetIsOfficialBuild(false);
1043 performer_.public_key_path_ = existing_file;
1044 install_plan_.public_key_rsa = "";
1045 EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1046 EXPECT_EQ(public_key, kExistingKey);
1047 // Same with official build -> kExistingKey
1048 fake_hardware_.SetIsOfficialBuild(true);
1049 EXPECT_TRUE(performer_.GetPublicKey(&public_key));
1050 EXPECT_EQ(public_key, kExistingKey);
1051
1052 // Non-official build, non-existing public-key, key in response
1053 // but invalid base64 -> false
1054 fake_hardware_.SetIsOfficialBuild(false);
1055 performer_.public_key_path_ = non_existing_file;
1056 install_plan_.public_key_rsa = "not-valid-base64";
1057 EXPECT_FALSE(performer_.GetPublicKey(&public_key));
1058 }
1059
TEST_F(DeltaPerformerTest,ConfVersionsMatch)1060 TEST_F(DeltaPerformerTest, ConfVersionsMatch) {
1061 // Test that the versions in update_engine.conf that is installed to the
1062 // image match the maximum supported delta versions in the update engine.
1063 uint32_t minor_version;
1064 brillo::KeyValueStore store;
1065 EXPECT_TRUE(store.Load(GetBuildArtifactsPath().Append("update_engine.conf")));
1066 EXPECT_TRUE(utils::GetMinorVersion(store, &minor_version));
1067 EXPECT_EQ(kMaxSupportedMinorPayloadVersion, minor_version);
1068
1069 string major_version_str;
1070 uint64_t major_version;
1071 EXPECT_TRUE(store.GetString("PAYLOAD_MAJOR_VERSION", &major_version_str));
1072 EXPECT_TRUE(base::StringToUint64(major_version_str, &major_version));
1073 EXPECT_EQ(kMaxSupportedMajorPayloadVersion, major_version);
1074 }
1075
1076 } // namespace chromeos_update_engine
1077