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