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