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