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