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