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 <sys/mount.h>
20
21 #include <algorithm>
22 #include <list>
23 #include <string>
24 #include <vector>
25
26 #include <base/files/file_path.h>
27 #include <base/files/file_util.h>
28 #include <android-base/stringprintf.h>
29 #include <gmock/gmock-matchers.h>
30 #include <google/protobuf/repeated_field.h>
31 #include <gtest/gtest.h>
32 #include <openssl/pem.h>
33
34 #include "update_engine/common/constants.h"
35 #include "update_engine/common/fake_boot_control.h"
36 #include "update_engine/common/fake_hardware.h"
37 #include "update_engine/common/fake_prefs.h"
38 #include "update_engine/common/mock_download_action.h"
39 #include "update_engine/common/mock_prefs.h"
40 #include "update_engine/common/test_utils.h"
41 #include "update_engine/common/testing_constants.h"
42 #include "update_engine/common/utils.h"
43 #include "update_engine/payload_consumer/install_plan.h"
44 #include "update_engine/payload_consumer/payload_constants.h"
45 #include "update_engine/payload_consumer/payload_metadata.h"
46 #include "update_engine/payload_generator/delta_diff_generator.h"
47 #include "update_engine/payload_generator/payload_signer.h"
48 #include "update_engine/update_metadata.pb.h"
49
50 namespace chromeos_update_engine {
51
52 using std::list;
53 using std::string;
54 using std::unique_ptr;
55 using std::vector;
56 using test_utils::GetBuildArtifactsPath;
57 using test_utils::kRandomString;
58 using test_utils::ScopedLoopMounter;
59 using test_utils::System;
60 using testing::_;
61 using testing::IsEmpty;
62 using testing::NiceMock;
63 using testing::Not;
64 using testing::Return;
65
66 static const uint32_t kDefaultKernelSize = 4096; // Something small for a test
67 // clang-format off
68 static const uint8_t kNewData[] = {'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
69 'n', 'e', 'w', ' ', 'd', 'a', 't', 'a', '.'};
70 // clang-format on
71
72 namespace {
73 struct DeltaState {
74 unique_ptr<ScopedTempFile> a_img;
75 unique_ptr<ScopedTempFile> b_img;
76 unique_ptr<ScopedTempFile> result_img;
77 size_t image_size;
78
79 unique_ptr<ScopedTempFile> delta_file;
80 // The in-memory copy of delta file.
81 brillo::Blob delta;
82 uint64_t metadata_size;
83 uint32_t metadata_signature_size;
84
85 unique_ptr<ScopedTempFile> old_kernel;
86 brillo::Blob old_kernel_data;
87
88 unique_ptr<ScopedTempFile> new_kernel;
89 brillo::Blob new_kernel_data;
90
91 unique_ptr<ScopedTempFile> result_kernel;
92 brillo::Blob result_kernel_data;
93 size_t kernel_size;
94
95 // The InstallPlan referenced by the DeltaPerformer. This needs to outlive
96 // the DeltaPerformer.
97 InstallPlan install_plan;
98
99 // Mock and fake instances used by the delta performer.
100 FakeBootControl fake_boot_control_;
101 FakeHardware fake_hardware_;
102 MockDownloadActionDelegate mock_delegate_;
103 };
104
105 enum SignatureTest {
106 kSignatureNone, // No payload signing.
107 kSignatureGenerator, // Sign the payload at generation time.
108 kSignatureGenerated, // Sign the payload after it's generated.
109 kSignatureGeneratedPlaceholder, // Insert placeholder signatures, then real.
110 kSignatureGeneratedPlaceholderMismatch, // Insert a wrong sized placeholder.
111 kSignatureGeneratedShell, // Sign the generated payload through shell cmds.
112 kSignatureGeneratedShellECKey, // Sign with a EC key through shell cmds.
113 kSignatureGeneratedShellBadKey, // Sign with a bad key through shell cmds.
114 kSignatureGeneratedShellRotateCl1, // Rotate key, test client v1
115 kSignatureGeneratedShellRotateCl2, // Rotate key, test client v2
116 };
117
118 enum OperationHashTest {
119 kInvalidOperationData,
120 kValidOperationData,
121 };
122
123 } // namespace
124
125 class DeltaPerformerIntegrationTest : public ::testing::Test {
126 public:
RunManifestValidation(const DeltaArchiveManifest & manifest,uint64_t major_version,ErrorCode expected)127 void RunManifestValidation(const DeltaArchiveManifest& manifest,
128 uint64_t major_version,
129 ErrorCode expected) {
130 FakePrefs prefs;
131 InstallPlan::Payload payload;
132 InstallPlan install_plan;
133 DeltaPerformer performer{&prefs,
134 nullptr,
135 &fake_hardware_,
136 nullptr,
137 &install_plan,
138 &payload,
139 false /* interactive*/};
140 // Delta performer will treat manifest as kDelta payload
141 // if it's a partial update.
142 payload.type = manifest.partial_update() ? InstallPayloadType::kDelta
143 : InstallPayloadType::kFull;
144
145 // The Manifest we are validating.
146 performer.manifest_.CopyFrom(manifest);
147 performer.major_payload_version_ = major_version;
148
149 ASSERT_EQ(expected, performer.ValidateManifest());
150 }
AddPartition(DeltaArchiveManifest * manifest,string name,int timestamp)151 void AddPartition(DeltaArchiveManifest* manifest,
152 string name,
153 int timestamp) {
154 auto& partition = *manifest->add_partitions();
155 partition.set_version(std::to_string(timestamp));
156 partition.set_partition_name(name);
157 }
158 FakeHardware fake_hardware_;
159 };
160
CompareFilesByBlock(const string & a_file,const string & b_file,size_t image_size)161 static void CompareFilesByBlock(const string& a_file,
162 const string& b_file,
163 size_t image_size) {
164 ASSERT_EQ(0U, image_size % kBlockSize);
165
166 brillo::Blob a_data, b_data;
167 ASSERT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file;
168 ASSERT_TRUE(utils::ReadFile(b_file, &b_data)) << "file failed: " << b_file;
169
170 EXPECT_GE(a_data.size(), image_size);
171 EXPECT_GE(b_data.size(), image_size);
172 for (size_t i = 0; i < image_size; i += kBlockSize) {
173 ASSERT_EQ(0U, i % kBlockSize);
174 brillo::Blob a_sub(&a_data[i], &a_data[i + kBlockSize]);
175 brillo::Blob b_sub(&b_data[i], &b_data[i + kBlockSize]);
176 ASSERT_EQ(a_sub, b_sub) << "Block " << (i / kBlockSize) << " differs";
177 }
178 if (::testing::Test::HasNonfatalFailure()) {
179 LOG(INFO) << "Compared filesystems with size " << image_size
180 << ", partition A " << a_file << " size: " << a_data.size()
181 << ", partition B " << b_file << " size: " << b_data.size();
182 }
183 }
184
WriteSparseFile(const string & path,off_t size)185 static bool WriteSparseFile(const string& path, off_t size) {
186 int fd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
187 TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
188 ScopedFdCloser fd_closer(&fd);
189 off_t rc = lseek(fd, size + 1, SEEK_SET);
190 TEST_AND_RETURN_FALSE_ERRNO(rc != static_cast<off_t>(-1));
191 int return_code = ftruncate(fd, size);
192 TEST_AND_RETURN_FALSE_ERRNO(return_code == 0);
193 return true;
194 }
195
WriteByteAtOffset(const string & path,off_t offset)196 static bool WriteByteAtOffset(const string& path, off_t offset) {
197 int fd = open(path.c_str(), O_CREAT | O_WRONLY, 0644);
198 TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
199 ScopedFdCloser fd_closer(&fd);
200 return utils::PWriteAll(fd, "\0", 1, offset);
201 }
202
InsertSignaturePlaceholder(size_t signature_size,const string & payload_path,uint64_t * out_metadata_size)203 static bool InsertSignaturePlaceholder(size_t signature_size,
204 const string& payload_path,
205 uint64_t* out_metadata_size) {
206 vector<brillo::Blob> signatures;
207 signatures.push_back(brillo::Blob(signature_size, 0));
208
209 return PayloadSigner::AddSignatureToPayload(payload_path,
210 {signature_size},
211 signatures,
212 {},
213 payload_path,
214 out_metadata_size);
215 }
216
SignGeneratedPayload(const string & payload_path,uint64_t * out_metadata_size)217 static void SignGeneratedPayload(const string& payload_path,
218 uint64_t* out_metadata_size) {
219 string private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
220 size_t signature_size{};
221 ASSERT_TRUE(PayloadSigner::GetMaximumSignatureSize(private_key_path,
222 &signature_size));
223 brillo::Blob metadata_hash, payload_hash;
224 ASSERT_TRUE(PayloadSigner::HashPayloadForSigning(
225 payload_path, {signature_size}, &payload_hash, &metadata_hash));
226 brillo::Blob metadata_signature, payload_signature;
227 ASSERT_TRUE(PayloadSigner::SignHash(
228 payload_hash, private_key_path, &payload_signature));
229 ASSERT_TRUE(PayloadSigner::SignHash(
230 metadata_hash, private_key_path, &metadata_signature));
231 ASSERT_TRUE(PayloadSigner::AddSignatureToPayload(payload_path,
232 {signature_size},
233 {payload_signature},
234 {metadata_signature},
235 payload_path,
236 out_metadata_size));
237 ASSERT_TRUE(PayloadSigner::VerifySignedPayload(
238 payload_path, GetBuildArtifactsPath(kUnittestPublicKeyPath)));
239 }
240
SignGeneratedShellPayloadWithKeys(const string & payload_path,const vector<string> & private_key_paths,const string & public_key_path,bool verification_success)241 static void SignGeneratedShellPayloadWithKeys(
242 const string& payload_path,
243 const vector<string>& private_key_paths,
244 const string& public_key_path,
245 bool verification_success) {
246 vector<string> signature_size_strings;
247 for (const auto& key_path : private_key_paths) {
248 size_t signature_size{};
249 ASSERT_TRUE(
250 PayloadSigner::GetMaximumSignatureSize(key_path, &signature_size));
251 signature_size_strings.push_back(
252 android::base::StringPrintf("%zu", signature_size));
253 }
254 string signature_size_string =
255 android::base::Join(signature_size_strings, ":");
256
257 ScopedTempFile hash_file("hash.XXXXXX"), metadata_hash_file("hash.XXXXXX");
258 string delta_generator_path = GetBuildArtifactsPath("delta_generator");
259 ASSERT_EQ(0,
260 System(android::base::StringPrintf(
261 "%s -in_file=%s -signature_size=%s -out_hash_file=%s "
262 "-out_metadata_hash_file=%s",
263 delta_generator_path.c_str(),
264 payload_path.c_str(),
265 signature_size_string.c_str(),
266 hash_file.path().c_str(),
267 metadata_hash_file.path().c_str())));
268
269 // Sign the hash with all private keys.
270 list<ScopedTempFile> sig_files, metadata_sig_files;
271 vector<string> sig_file_paths, metadata_sig_file_paths;
272 for (const auto& key_path : private_key_paths) {
273 brillo::Blob hash, signature;
274 ASSERT_TRUE(utils::ReadFile(hash_file.path(), &hash));
275 ASSERT_TRUE(PayloadSigner::SignHash(hash, key_path, &signature));
276
277 sig_files.emplace_back("signature.XXXXXX");
278 ASSERT_TRUE(
279 test_utils::WriteFileVector(sig_files.back().path(), signature));
280 sig_file_paths.push_back(sig_files.back().path());
281
282 brillo::Blob metadata_hash, metadata_signature;
283 ASSERT_TRUE(utils::ReadFile(metadata_hash_file.path(), &metadata_hash));
284 ASSERT_TRUE(
285 PayloadSigner::SignHash(metadata_hash, key_path, &metadata_signature));
286
287 metadata_sig_files.emplace_back("metadata_signature.XXXXXX");
288 ASSERT_TRUE(test_utils::WriteFileVector(metadata_sig_files.back().path(),
289 metadata_signature));
290 metadata_sig_file_paths.push_back(metadata_sig_files.back().path());
291 }
292 string sig_files_string = android::base::Join(sig_file_paths, ":");
293 string metadata_sig_files_string =
294 android::base::Join(metadata_sig_file_paths, ":");
295
296 // Add the signature to the payload.
297 ASSERT_EQ(
298 0,
299 System(android::base::StringPrintf("%s --signature_size=%s -in_file=%s "
300 "-payload_signature_file=%s "
301 "-metadata_signature_file=%s "
302 "-out_file=%s",
303 delta_generator_path.c_str(),
304 signature_size_string.c_str(),
305 payload_path.c_str(),
306 sig_files_string.c_str(),
307 metadata_sig_files_string.c_str(),
308 payload_path.c_str())));
309
310 int verify_result =
311 System(android::base::StringPrintf("%s -in_file=%s -public_key=%s",
312 delta_generator_path.c_str(),
313 payload_path.c_str(),
314 public_key_path.c_str()));
315
316 if (verification_success) {
317 ASSERT_EQ(0, verify_result);
318 } else {
319 ASSERT_NE(0, verify_result);
320 }
321 }
322
SignGeneratedShellPayload(SignatureTest signature_test,const string & payload_path)323 static void SignGeneratedShellPayload(SignatureTest signature_test,
324 const string& payload_path) {
325 vector<SignatureTest> supported_test = {
326 kSignatureGeneratedShell,
327 kSignatureGeneratedShellBadKey,
328 kSignatureGeneratedShellECKey,
329 kSignatureGeneratedShellRotateCl1,
330 kSignatureGeneratedShellRotateCl2,
331 };
332 ASSERT_TRUE(std::find(supported_test.begin(),
333 supported_test.end(),
334 signature_test) != supported_test.end());
335
336 string private_key_path;
337 if (signature_test == kSignatureGeneratedShellBadKey) {
338 ASSERT_TRUE(utils::MakeTempFile("key.XXXXXX", &private_key_path, nullptr));
339 } else if (signature_test == kSignatureGeneratedShellECKey) {
340 private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyECPath);
341 } else {
342 private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
343 }
344 ScopedPathUnlinker key_unlinker(private_key_path);
345 key_unlinker.set_should_remove(signature_test ==
346 kSignatureGeneratedShellBadKey);
347
348 // Generates a new private key that will not match the public key.
349 if (signature_test == kSignatureGeneratedShellBadKey) {
350 LOG(INFO) << "Generating a mismatched private key.";
351 // The code below executes the equivalent of:
352 // openssl genrsa -out <private_key_path> 2048
353 RSA* rsa = RSA_new();
354 BIGNUM* e = BN_new();
355 ASSERT_EQ(1, BN_set_word(e, RSA_F4));
356 ASSERT_EQ(1, RSA_generate_key_ex(rsa, 2048, e, nullptr));
357 BN_free(e);
358 FILE* fprikey = fopen(private_key_path.c_str(), "w");
359 EXPECT_NE(nullptr, fprikey);
360 ASSERT_EQ(1,
361 PEM_write_RSAPrivateKey(
362 fprikey, rsa, nullptr, nullptr, 0, nullptr, nullptr));
363 fclose(fprikey);
364 RSA_free(rsa);
365 }
366
367 vector<string> private_key_paths = {private_key_path};
368 if (signature_test == kSignatureGeneratedShellRotateCl1 ||
369 signature_test == kSignatureGeneratedShellRotateCl2) {
370 private_key_paths.push_back(
371 GetBuildArtifactsPath(kUnittestPrivateKey2Path));
372 }
373
374 string public_key;
375 if (signature_test == kSignatureGeneratedShellRotateCl2) {
376 public_key = GetBuildArtifactsPath(kUnittestPublicKey2Path);
377 } else if (signature_test == kSignatureGeneratedShellECKey) {
378 public_key = GetBuildArtifactsPath(kUnittestPublicKeyECPath);
379 } else {
380 public_key = GetBuildArtifactsPath(kUnittestPublicKeyPath);
381 }
382
383 bool verification_success = signature_test != kSignatureGeneratedShellBadKey;
384 SignGeneratedShellPayloadWithKeys(
385 payload_path, private_key_paths, public_key, verification_success);
386 }
387
GenerateDeltaFile(bool full_kernel,bool full_rootfs,ssize_t chunk_size,SignatureTest signature_test,DeltaState * state,uint32_t minor_version)388 static void GenerateDeltaFile(bool full_kernel,
389 bool full_rootfs,
390 ssize_t chunk_size,
391 SignatureTest signature_test,
392 DeltaState* state,
393 uint32_t minor_version) {
394 state->a_img.reset(new ScopedTempFile("a_img.XXXXXX"));
395 state->b_img.reset(new ScopedTempFile("b_img.XXXXXX"));
396
397 // result_img is used in minor version 2. Instead of applying the update
398 // in-place on A, we apply it to a new image, result_img.
399 state->result_img.reset(new ScopedTempFile("result_img.XXXXXX"));
400
401 ASSERT_TRUE(
402 base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
403 base::FilePath(state->a_img->path())));
404
405 state->image_size = utils::FileSize(state->a_img->path());
406
407 // Make some changes to the A image.
408 {
409 string a_mnt;
410 ScopedLoopMounter b_mounter(state->a_img->path(), &a_mnt, 0);
411
412 brillo::Blob hardtocompress;
413 while (hardtocompress.size() < 3 * kBlockSize) {
414 hardtocompress.insert(hardtocompress.end(),
415 std::begin(kRandomString),
416 std::end(kRandomString));
417 }
418 ASSERT_TRUE(utils::WriteFile(
419 android::base::StringPrintf("%s/hardtocompress", a_mnt.c_str()).c_str(),
420 hardtocompress.data(),
421 hardtocompress.size()));
422
423 brillo::Blob zeros(16 * 1024, 0);
424 ASSERT_EQ(static_cast<int>(zeros.size()),
425 base::WriteFile(base::FilePath(android::base::StringPrintf(
426 "%s/move-to-sparse", a_mnt.c_str())),
427 reinterpret_cast<const char*>(zeros.data()),
428 zeros.size()));
429
430 ASSERT_TRUE(WriteSparseFile(
431 android::base::StringPrintf("%s/move-from-sparse", a_mnt.c_str()),
432 16 * 1024));
433
434 ASSERT_TRUE(WriteByteAtOffset(
435 android::base::StringPrintf("%s/move-semi-sparse", a_mnt.c_str()),
436 4096));
437
438 // Write 1 MiB of 0xff to try to catch the case where writing a bsdiff
439 // patch fails to zero out the final block.
440 brillo::Blob ones(1024 * 1024, 0xff);
441 ASSERT_TRUE(utils::WriteFile(
442 android::base::StringPrintf("%s/ones", a_mnt.c_str()).c_str(),
443 ones.data(),
444 ones.size()));
445 }
446
447 // Create a result image with image_size bytes of garbage.
448 brillo::Blob ones(state->image_size, 0xff);
449 ASSERT_TRUE(utils::WriteFile(
450 state->result_img->path().c_str(), ones.data(), ones.size()));
451 ASSERT_EQ(utils::FileSize(state->a_img->path()),
452 utils::FileSize(state->result_img->path()));
453
454 ASSERT_TRUE(
455 base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
456 base::FilePath(state->b_img->path())));
457 {
458 // Make some changes to the B image.
459 string b_mnt;
460 ScopedLoopMounter b_mounter(state->b_img->path(), &b_mnt, 0);
461 base::FilePath mnt_path(b_mnt);
462
463 ASSERT_TRUE(base::CopyFile(mnt_path.Append("regular-small"),
464 mnt_path.Append("regular-small2")));
465 #if BASE_VER < 800000
466 ASSERT_TRUE(base::DeleteFile(mnt_path.Append("regular-small"), false));
467 #else
468 ASSERT_TRUE(base::DeleteFile(mnt_path.Append("regular-small")));
469 #endif
470 ASSERT_TRUE(base::Move(mnt_path.Append("regular-small2"),
471 mnt_path.Append("regular-small")));
472 ASSERT_TRUE(
473 test_utils::WriteFileString(mnt_path.Append("foo").value(), "foo"));
474 ASSERT_EQ(0, base::WriteFile(mnt_path.Append("emptyfile"), "", 0));
475
476 ASSERT_TRUE(
477 WriteSparseFile(mnt_path.Append("fullsparse").value(), 1024 * 1024));
478 ASSERT_TRUE(
479 WriteSparseFile(mnt_path.Append("move-to-sparse").value(), 16 * 1024));
480
481 brillo::Blob zeros(16 * 1024, 0);
482 ASSERT_EQ(static_cast<int>(zeros.size()),
483 base::WriteFile(mnt_path.Append("move-from-sparse"),
484 reinterpret_cast<const char*>(zeros.data()),
485 zeros.size()));
486
487 ASSERT_TRUE(
488 WriteByteAtOffset(mnt_path.Append("move-semi-sparse").value(), 4096));
489 ASSERT_TRUE(WriteByteAtOffset(mnt_path.Append("partsparse").value(), 4096));
490
491 ASSERT_TRUE(
492 base::CopyFile(mnt_path.Append("regular-16k"), mnt_path.Append("tmp")));
493 ASSERT_TRUE(base::Move(mnt_path.Append("tmp"),
494 mnt_path.Append("link-hard-regular-16k")));
495
496 #if BASE_VER < 800000
497 ASSERT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink"), false));
498 #else
499 ASSERT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink")));
500 #endif
501 ASSERT_TRUE(test_utils::WriteFileString(
502 mnt_path.Append("link-short_symlink").value(), "foobar"));
503
504 brillo::Blob hardtocompress;
505 while (hardtocompress.size() < 3 * kBlockSize) {
506 hardtocompress.insert(hardtocompress.end(),
507 std::begin(kRandomString),
508 std::end(kRandomString));
509 }
510 ASSERT_TRUE(utils::WriteFile(
511 android::base::StringPrintf("%s/hardtocompress", b_mnt.c_str()).c_str(),
512 hardtocompress.data(),
513 hardtocompress.size()));
514 }
515
516 state->old_kernel.reset(new ScopedTempFile("old_kernel.XXXXXX"));
517 state->new_kernel.reset(new ScopedTempFile("new_kernel.XXXXXX"));
518 state->result_kernel.reset(new ScopedTempFile("result_kernel.XXXXXX"));
519 state->kernel_size = kDefaultKernelSize;
520 state->old_kernel_data.resize(kDefaultKernelSize);
521 state->new_kernel_data.resize(state->old_kernel_data.size());
522 state->result_kernel_data.resize(state->old_kernel_data.size());
523 test_utils::FillWithData(&state->old_kernel_data);
524 test_utils::FillWithData(&state->new_kernel_data);
525 test_utils::FillWithData(&state->result_kernel_data);
526
527 // change the new kernel data
528 std::copy(
529 std::begin(kNewData), std::end(kNewData), state->new_kernel_data.begin());
530
531 // Write kernels to disk
532 ASSERT_TRUE(utils::WriteFile(state->old_kernel->path().c_str(),
533 state->old_kernel_data.data(),
534 state->old_kernel_data.size()));
535 ASSERT_TRUE(utils::WriteFile(state->new_kernel->path().c_str(),
536 state->new_kernel_data.data(),
537 state->new_kernel_data.size()));
538 ASSERT_TRUE(utils::WriteFile(state->result_kernel->path().c_str(),
539 state->result_kernel_data.data(),
540 state->result_kernel_data.size()));
541
542 state->delta_file.reset(new ScopedTempFile("delta.XXXXXX"));
543 {
544 const string private_key =
545 signature_test == kSignatureGenerator
546 ? GetBuildArtifactsPath(kUnittestPrivateKeyPath)
547 : "";
548
549 PayloadGenerationConfig payload_config;
550 payload_config.is_delta = !full_rootfs;
551 payload_config.hard_chunk_size = chunk_size;
552 payload_config.rootfs_partition_size = kRootFSPartitionSize;
553 payload_config.version.major = kBrilloMajorPayloadVersion;
554 payload_config.version.minor = minor_version;
555 if (!full_rootfs) {
556 payload_config.source.partitions.emplace_back(kPartitionNameRoot);
557 payload_config.source.partitions.emplace_back(kPartitionNameKernel);
558 payload_config.source.partitions.front().path = state->a_img->path();
559 if (!full_kernel)
560 payload_config.source.partitions.back().path =
561 state->old_kernel->path();
562 ASSERT_TRUE(payload_config.source.LoadImageSize());
563 for (PartitionConfig& part : payload_config.source.partitions)
564 ASSERT_TRUE(part.OpenFilesystem());
565 } else {
566 if (payload_config.hard_chunk_size == -1)
567 // Use 1 MiB chunk size for the full unittests.
568 payload_config.hard_chunk_size = 1024 * 1024;
569 }
570 payload_config.target.partitions.emplace_back(kPartitionNameRoot);
571 payload_config.target.partitions.back().path = state->b_img->path();
572 payload_config.target.partitions.emplace_back(kPartitionNameKernel);
573 payload_config.target.partitions.back().path = state->new_kernel->path();
574 ASSERT_TRUE(payload_config.target.LoadImageSize());
575 for (PartitionConfig& part : payload_config.target.partitions)
576 ASSERT_TRUE(part.OpenFilesystem());
577
578 ASSERT_TRUE(payload_config.Validate());
579 ASSERT_TRUE(GenerateUpdatePayloadFile(payload_config,
580 state->delta_file->path(),
581 private_key,
582 &state->metadata_size));
583 }
584 // Extend the "partitions" holding the file system a bit.
585 ASSERT_EQ(0,
586 HANDLE_EINTR(truncate(state->a_img->path().c_str(),
587 state->image_size + 1024 * 1024)));
588 ASSERT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
589 utils::FileSize(state->a_img->path()));
590 ASSERT_EQ(0,
591 HANDLE_EINTR(truncate(state->b_img->path().c_str(),
592 state->image_size + 1024 * 1024)));
593 ASSERT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
594 utils::FileSize(state->b_img->path()));
595
596 if (signature_test == kSignatureGeneratedPlaceholder ||
597 signature_test == kSignatureGeneratedPlaceholderMismatch) {
598 size_t signature_size{};
599 ASSERT_TRUE(PayloadSigner::GetMaximumSignatureSize(
600 GetBuildArtifactsPath(kUnittestPrivateKeyPath), &signature_size));
601 LOG(INFO) << "Inserting placeholder signature.";
602 ASSERT_TRUE(InsertSignaturePlaceholder(
603 signature_size, state->delta_file->path(), &state->metadata_size));
604
605 if (signature_test == kSignatureGeneratedPlaceholderMismatch) {
606 signature_size -= 1;
607 LOG(INFO) << "Inserting mismatched placeholder signature.";
608 ASSERT_TRUE(InsertSignaturePlaceholder(
609 signature_size, state->delta_file->path(), &state->metadata_size));
610 return;
611 }
612 }
613
614 if (signature_test == kSignatureGenerated ||
615 signature_test == kSignatureGeneratedPlaceholder ||
616 signature_test == kSignatureGeneratedPlaceholderMismatch) {
617 // Generate the signed payload and update the metadata size in state to
618 // reflect the new size after adding the signature operation to the
619 // manifest.
620 LOG(INFO) << "Signing payload.";
621 SignGeneratedPayload(state->delta_file->path(), &state->metadata_size);
622 } else if (signature_test == kSignatureGeneratedShell ||
623 signature_test == kSignatureGeneratedShellECKey ||
624 signature_test == kSignatureGeneratedShellBadKey ||
625 signature_test == kSignatureGeneratedShellRotateCl1 ||
626 signature_test == kSignatureGeneratedShellRotateCl2) {
627 SignGeneratedShellPayload(signature_test, state->delta_file->path());
628 }
629 }
630
ApplyDeltaFile(bool full_kernel,bool full_rootfs,SignatureTest signature_test,DeltaState * state,bool hash_checks_mandatory,OperationHashTest op_hash_test,DeltaPerformer ** performer,uint32_t minor_version)631 static void ApplyDeltaFile(bool full_kernel,
632 bool full_rootfs,
633 SignatureTest signature_test,
634 DeltaState* state,
635 bool hash_checks_mandatory,
636 OperationHashTest op_hash_test,
637 DeltaPerformer** performer,
638 uint32_t minor_version) {
639 // Check the metadata.
640 {
641 ASSERT_TRUE(utils::ReadFile(state->delta_file->path(), &state->delta));
642 PayloadMetadata payload_metadata;
643 ASSERT_TRUE(payload_metadata.ParsePayloadHeader(state->delta));
644 state->metadata_size = payload_metadata.GetMetadataSize();
645 LOG(INFO) << "Metadata size: " << state->metadata_size;
646 LOG(INFO) << "Payload size: " << state->delta.size();
647 state->metadata_signature_size =
648 payload_metadata.GetMetadataSignatureSize();
649 LOG(INFO) << "Metadata signature size: " << state->metadata_signature_size;
650
651 DeltaArchiveManifest manifest;
652 ASSERT_TRUE(payload_metadata.GetManifest(state->delta, &manifest));
653 if (signature_test == kSignatureNone) {
654 ASSERT_FALSE(manifest.has_signatures_offset());
655 ASSERT_FALSE(manifest.has_signatures_size());
656 } else {
657 ASSERT_TRUE(manifest.has_signatures_offset());
658 ASSERT_TRUE(manifest.has_signatures_size());
659 Signatures sigs_message;
660 ASSERT_TRUE(sigs_message.ParseFromArray(
661 &state->delta[state->metadata_size + state->metadata_signature_size +
662 manifest.signatures_offset()],
663 manifest.signatures_size()));
664 if (signature_test == kSignatureGeneratedShellRotateCl1 ||
665 signature_test == kSignatureGeneratedShellRotateCl2)
666 ASSERT_EQ(2, sigs_message.signatures_size());
667 else
668 ASSERT_EQ(1, sigs_message.signatures_size());
669 const Signatures::Signature& signature = sigs_message.signatures(0);
670
671 vector<string> key_paths{GetBuildArtifactsPath(kUnittestPrivateKeyPath)};
672 if (signature_test == kSignatureGeneratedShellECKey) {
673 key_paths = {GetBuildArtifactsPath(kUnittestPrivateKeyECPath)};
674 } else if (signature_test == kSignatureGeneratedShellRotateCl1 ||
675 signature_test == kSignatureGeneratedShellRotateCl2) {
676 key_paths.push_back(GetBuildArtifactsPath(kUnittestPrivateKey2Path));
677 }
678 uint64_t expected_sig_data_length = 0;
679 ASSERT_TRUE(PayloadSigner::SignatureBlobLength(
680 key_paths, &expected_sig_data_length));
681 ASSERT_EQ(expected_sig_data_length, manifest.signatures_size());
682 ASSERT_FALSE(signature.data().empty());
683 }
684
685 // TODO(ahassani): Make |DeltaState| into a partition list kind of struct
686 // instead of hardcoded kernel/rootfs so its cleaner and we can make the
687 // following code into a helper function instead.
688 const auto& kernel_part = *std::find_if(
689 manifest.partitions().begin(),
690 manifest.partitions().end(),
691 [](const PartitionUpdate& partition) {
692 return partition.partition_name() == kPartitionNameKernel;
693 });
694 if (full_kernel) {
695 ASSERT_FALSE(kernel_part.has_old_partition_info());
696 } else {
697 ASSERT_EQ(state->old_kernel_data.size(),
698 kernel_part.old_partition_info().size());
699 ASSERT_FALSE(kernel_part.old_partition_info().hash().empty());
700 }
701 ASSERT_EQ(state->new_kernel_data.size(),
702 kernel_part.new_partition_info().size());
703 ASSERT_FALSE(kernel_part.new_partition_info().hash().empty());
704
705 const auto& rootfs_part =
706 *std::find_if(manifest.partitions().begin(),
707 manifest.partitions().end(),
708 [](const PartitionUpdate& partition) {
709 return partition.partition_name() == kPartitionNameRoot;
710 });
711 if (full_rootfs) {
712 ASSERT_FALSE(rootfs_part.has_old_partition_info());
713 } else {
714 ASSERT_FALSE(rootfs_part.old_partition_info().hash().empty());
715 }
716 ASSERT_FALSE(rootfs_part.new_partition_info().hash().empty());
717 }
718
719 NiceMock<MockPrefs> prefs;
720 ON_CALL(prefs, SetInt64(kPrefsManifestMetadataSize, -1))
721 .WillByDefault(Return(true));
722 ON_CALL(prefs, SetInt64(kPrefsUpdateCheckResponseHash, -1))
723 .WillByDefault(Return(true));
724 ON_CALL(prefs, GetString(kPrefsUpdateCheckResponseHash, _))
725 .WillByDefault(Return(true));
726 ON_CALL(prefs, GetString(kPrefsDynamicPartitionMetadataUpdated, _))
727 .WillByDefault(Return(true));
728
729 // Set default expectation to ignore uninteresting calls to
730 // SetString/SetInt64. When starting an update delta_performer might reset
731 // update checkpoints, which results in a lot of calls with empty string or
732 // integer -1. Ignore these.
733 EXPECT_CALL(prefs, SetString(_, IsEmpty())).WillRepeatedly(Return(true));
734 EXPECT_CALL(prefs, SetInt64(_, -1)).WillRepeatedly(Return(true));
735 EXPECT_CALL(prefs, SetInt64(_, 0)).WillRepeatedly(Return(true));
736
737 EXPECT_CALL(prefs, SetInt64(kPrefsManifestMetadataSize, state->metadata_size))
738 .WillOnce(Return(true));
739 EXPECT_CALL(
740 prefs,
741 SetInt64(kPrefsManifestSignatureSize, state->metadata_signature_size))
742 .WillOnce(Return(true));
743 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextOperation, _))
744 .WillRepeatedly(Return(true));
745 EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextOperation, _))
746 .WillOnce(Return(false));
747 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataOffset, _))
748 .WillRepeatedly(Return(true));
749 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataLength, _))
750 .WillRepeatedly(Return(true));
751 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSHA256Context, _))
752 .WillRepeatedly(Return(true));
753 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignedSHA256Context, _))
754 .WillRepeatedly(Return(true));
755 EXPECT_CALL(prefs, SetString(kPrefsDynamicPartitionMetadataUpdated, _))
756 .WillRepeatedly(Return(true));
757 EXPECT_CALL(prefs,
758 SetString(kPrefsManifestBytes,
759 testing::SizeIs(state->metadata_signature_size +
760 state->metadata_size)))
761 .WillRepeatedly(Return(true));
762 if (op_hash_test == kValidOperationData && signature_test != kSignatureNone) {
763 EXPECT_CALL(prefs,
764 SetString(kPrefsUpdateStateSignatureBlob, Not(IsEmpty())))
765 .WillRepeatedly(Return(true));
766 }
767
768 EXPECT_CALL(state->mock_delegate_, ShouldCancel(_))
769 .WillRepeatedly(Return(false));
770
771 // Update the A image in place.
772 InstallPlan* install_plan = &state->install_plan;
773 install_plan->hash_checks_mandatory = hash_checks_mandatory;
774 install_plan->payloads = {{.size = state->delta.size(),
775 .metadata_size = state->metadata_size,
776 .type = (full_kernel && full_rootfs)
777 ? InstallPayloadType::kFull
778 : InstallPayloadType::kDelta}};
779 install_plan->source_slot = 0;
780 install_plan->target_slot = 1;
781
782 InstallPlan::Partition root_part;
783 root_part.name = kPartitionNameRoot;
784
785 InstallPlan::Partition kernel_part;
786 kernel_part.name = kPartitionNameKernel;
787
788 LOG(INFO) << "Setting payload metadata size in Omaha = "
789 << state->metadata_size;
790 ASSERT_TRUE(PayloadSigner::GetMetadataSignature(
791 state->delta.data(),
792 state->metadata_size,
793 (signature_test == kSignatureGeneratedShellECKey)
794 ? GetBuildArtifactsPath(kUnittestPrivateKeyECPath)
795 : GetBuildArtifactsPath(kUnittestPrivateKeyPath),
796 &install_plan->payloads[0].metadata_signature));
797 ASSERT_FALSE(install_plan->payloads[0].metadata_signature.empty());
798
799 *performer = new DeltaPerformer(&prefs,
800 &state->fake_boot_control_,
801 &state->fake_hardware_,
802 &state->mock_delegate_,
803 install_plan,
804 &install_plan->payloads[0],
805 false /* interactive */,
806 "");
807 string public_key_path = signature_test == kSignatureGeneratedShellECKey
808 ? GetBuildArtifactsPath(kUnittestPublicKeyECPath)
809 : GetBuildArtifactsPath(kUnittestPublicKeyPath);
810 ASSERT_TRUE(utils::FileExists(public_key_path.c_str()));
811 (*performer)->set_public_key_path(public_key_path);
812
813 ASSERT_EQ(
814 static_cast<off_t>(state->image_size),
815 HashCalculator::RawHashOfFile(
816 state->a_img->path(), state->image_size, &root_part.source_hash));
817 ASSERT_TRUE(HashCalculator::RawHashOfData(state->old_kernel_data,
818 &kernel_part.source_hash));
819
820 // The partitions should be empty before DeltaPerformer.
821 install_plan->partitions.clear();
822
823 state->fake_boot_control_.SetPartitionDevice(
824 kPartitionNameRoot, install_plan->source_slot, state->a_img->path());
825 state->fake_boot_control_.SetPartitionDevice(kPartitionNameKernel,
826 install_plan->source_slot,
827 state->old_kernel->path());
828 state->fake_boot_control_.SetPartitionDevice(
829 kPartitionNameRoot, install_plan->target_slot, state->result_img->path());
830 state->fake_boot_control_.SetPartitionDevice(kPartitionNameKernel,
831 install_plan->target_slot,
832 state->result_kernel->path());
833
834 ErrorCode expected_error{}, actual_error{};
835 bool continue_writing{};
836 switch (op_hash_test) {
837 case kInvalidOperationData: {
838 // Muck with some random offset post the metadata size so that
839 // some operation hash will result in a mismatch.
840 int some_offset = state->metadata_size + 300;
841 LOG(INFO) << "Tampered value at offset: " << some_offset;
842 state->delta[some_offset]++;
843 expected_error = ErrorCode::kDownloadOperationHashMismatch;
844 continue_writing = false;
845 break;
846 }
847
848 case kValidOperationData:
849 default:
850 // no change.
851 expected_error = ErrorCode::kSuccess;
852 continue_writing = true;
853 break;
854 }
855
856 // Write at some number of bytes per operation. Arbitrarily chose 5.
857 const size_t kBytesPerWrite = 5;
858 for (size_t i = 0; i < state->delta.size(); i += kBytesPerWrite) {
859 size_t count = std::min(state->delta.size() - i, kBytesPerWrite);
860 bool write_succeeded =
861 ((*performer)->Write(&state->delta[i], count, &actual_error));
862 // Normally write_succeeded should be true every time and
863 // actual_error should be ErrorCode::kSuccess. If so, continue the loop.
864 // But if we seeded an operation hash error above, then write_succeeded
865 // will be false. The failure may happen at any operation n. So, all
866 // Writes until n-1 should succeed and the nth operation will fail with
867 // actual_error. In this case, we should bail out of the loop because
868 // we cannot proceed applying the delta.
869 if (!write_succeeded) {
870 LOG(INFO) << "Write failed. Checking if it failed with expected error";
871 ASSERT_EQ(expected_error, actual_error);
872 if (!continue_writing) {
873 LOG(INFO) << "Cannot continue writing. Bailing out.";
874 break;
875 }
876 }
877
878 ASSERT_EQ(ErrorCode::kSuccess, actual_error);
879 }
880
881 // If we had continued all the way through, Close should succeed.
882 // Otherwise, it should fail. Check appropriately.
883 bool close_result = (*performer)->Close();
884 if (continue_writing)
885 ASSERT_EQ(0, close_result);
886 else
887 ASSERT_LE(0, close_result);
888 }
889
VerifyPayloadResult(DeltaPerformer * performer,DeltaState * state,ErrorCode expected_result,uint32_t minor_version)890 void VerifyPayloadResult(DeltaPerformer* performer,
891 DeltaState* state,
892 ErrorCode expected_result,
893 uint32_t minor_version) {
894 if (!performer) {
895 ASSERT_TRUE(!"Skipping payload verification since performer is null.");
896 return;
897 }
898
899 LOG(INFO) << "Verifying payload for expected result " << expected_result;
900 brillo::Blob expected_hash;
901 HashCalculator::RawHashOfData(state->delta, &expected_hash);
902 ASSERT_EQ(expected_result,
903 performer->VerifyPayload(expected_hash, state->delta.size()));
904 LOG(INFO) << "Verified payload.";
905
906 if (expected_result != ErrorCode::kSuccess) {
907 // no need to verify new partition if VerifyPayload failed.
908 return;
909 }
910 ASSERT_NO_FATAL_FAILURE(CompareFilesByBlock(state->result_kernel->path(),
911 state->new_kernel->path(),
912 state->kernel_size));
913 ASSERT_NO_FATAL_FAILURE(CompareFilesByBlock(
914 state->result_img->path(), state->b_img->path(), state->image_size));
915
916 brillo::Blob updated_kernel_partition;
917 ASSERT_TRUE(
918 utils::ReadFile(state->result_kernel->path(), &updated_kernel_partition));
919 ASSERT_GE(updated_kernel_partition.size(), std::size(kNewData));
920 ASSERT_TRUE(std::equal(std::begin(kNewData),
921 std::end(kNewData),
922 updated_kernel_partition.begin()));
923
924 const auto& partitions = state->install_plan.partitions;
925 ASSERT_EQ(2U, partitions.size());
926 ASSERT_EQ(kPartitionNameRoot, partitions[0].name);
927 ASSERT_EQ(kPartitionNameKernel, partitions[1].name);
928
929 ASSERT_EQ(kDefaultKernelSize, partitions[1].target_size);
930 brillo::Blob expected_new_kernel_hash;
931 ASSERT_TRUE(HashCalculator::RawHashOfData(state->new_kernel_data,
932 &expected_new_kernel_hash));
933 ASSERT_EQ(expected_new_kernel_hash, partitions[1].target_hash);
934
935 ASSERT_EQ(state->image_size, partitions[0].target_size);
936 brillo::Blob expected_new_rootfs_hash;
937 ASSERT_EQ(
938 static_cast<off_t>(state->image_size),
939 HashCalculator::RawHashOfFile(
940 state->b_img->path(), state->image_size, &expected_new_rootfs_hash));
941 ASSERT_EQ(expected_new_rootfs_hash, partitions[0].target_hash);
942 }
943
VerifyPayload(DeltaPerformer * performer,DeltaState * state,SignatureTest signature_test,uint32_t minor_version)944 void VerifyPayload(DeltaPerformer* performer,
945 DeltaState* state,
946 SignatureTest signature_test,
947 uint32_t minor_version) {
948 ErrorCode expected_result = ErrorCode::kSuccess;
949 switch (signature_test) {
950 case kSignatureNone:
951 expected_result = ErrorCode::kSignedDeltaPayloadExpectedError;
952 break;
953 case kSignatureGeneratedShellBadKey:
954 expected_result = ErrorCode::kDownloadPayloadPubKeyVerificationError;
955 break;
956 default:
957 break; // appease gcc
958 }
959
960 ASSERT_NO_FATAL_FAILURE(
961 VerifyPayloadResult(performer, state, expected_result, minor_version));
962 }
963
DoSmallImageTest(bool full_kernel,bool full_rootfs,ssize_t chunk_size,SignatureTest signature_test,bool hash_checks_mandatory,uint32_t minor_version)964 void DoSmallImageTest(bool full_kernel,
965 bool full_rootfs,
966 ssize_t chunk_size,
967 SignatureTest signature_test,
968 bool hash_checks_mandatory,
969 uint32_t minor_version) {
970 DeltaState state;
971 DeltaPerformer* performer = nullptr;
972 ASSERT_NO_FATAL_FAILURE(GenerateDeltaFile(full_kernel,
973 full_rootfs,
974 chunk_size,
975 signature_test,
976 &state,
977 minor_version));
978
979 ASSERT_NO_FATAL_FAILURE(ApplyDeltaFile(full_kernel,
980 full_rootfs,
981 signature_test,
982 &state,
983 hash_checks_mandatory,
984 kValidOperationData,
985 &performer,
986 minor_version));
987 ASSERT_NO_FATAL_FAILURE(
988 VerifyPayload(performer, &state, signature_test, minor_version));
989 delete performer;
990 }
991
DoOperationHashMismatchTest(OperationHashTest op_hash_test,bool hash_checks_mandatory)992 void DoOperationHashMismatchTest(OperationHashTest op_hash_test,
993 bool hash_checks_mandatory) {
994 DeltaState state;
995 uint64_t minor_version = kFullPayloadMinorVersion;
996 GenerateDeltaFile(true, true, -1, kSignatureGenerated, &state, minor_version);
997 DeltaPerformer* performer = nullptr;
998 ASSERT_NO_FATAL_FAILURE(ApplyDeltaFile(true,
999 true,
1000 kSignatureGenerated,
1001 &state,
1002 hash_checks_mandatory,
1003 op_hash_test,
1004 &performer,
1005 minor_version));
1006 delete performer;
1007 }
1008
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageTest)1009 TEST_F(DeltaPerformerIntegrationTest, RunAsRootSmallImageTest) {
1010 DoSmallImageTest(
1011 false, false, -1, kSignatureGenerator, false, kSourceMinorPayloadVersion);
1012 }
1013
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignaturePlaceholderTest)1014 TEST_F(DeltaPerformerIntegrationTest,
1015 RunAsRootSmallImageSignaturePlaceholderTest) {
1016 DoSmallImageTest(false,
1017 false,
1018 -1,
1019 kSignatureGeneratedPlaceholder,
1020 false,
1021 kSourceMinorPayloadVersion);
1022 }
1023
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignaturePlaceholderMismatchTest)1024 TEST_F(DeltaPerformerIntegrationTest,
1025 RunAsRootSmallImageSignaturePlaceholderMismatchTest) {
1026 DeltaState state;
1027 GenerateDeltaFile(false,
1028 false,
1029 -1,
1030 kSignatureGeneratedPlaceholderMismatch,
1031 &state,
1032 kSourceMinorPayloadVersion);
1033 }
1034
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageChunksTest)1035 TEST_F(DeltaPerformerIntegrationTest, RunAsRootSmallImageChunksTest) {
1036 DoSmallImageTest(false,
1037 false,
1038 kBlockSize,
1039 kSignatureGenerator,
1040 false,
1041 kSourceMinorPayloadVersion);
1042 }
1043
TEST_F(DeltaPerformerIntegrationTest,RunAsRootFullKernelSmallImageTest)1044 TEST_F(DeltaPerformerIntegrationTest, RunAsRootFullKernelSmallImageTest) {
1045 DoSmallImageTest(
1046 true, false, -1, kSignatureGenerator, false, kSourceMinorPayloadVersion);
1047 }
1048
TEST_F(DeltaPerformerIntegrationTest,RunAsRootFullSmallImageTest)1049 TEST_F(DeltaPerformerIntegrationTest, RunAsRootFullSmallImageTest) {
1050 DoSmallImageTest(
1051 true, true, -1, kSignatureGenerator, true, kFullPayloadMinorVersion);
1052 }
1053
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignNoneTest)1054 TEST_F(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignNoneTest) {
1055 DoSmallImageTest(
1056 false, false, -1, kSignatureNone, false, kSourceMinorPayloadVersion);
1057 }
1058
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedTest)1059 TEST_F(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedTest) {
1060 DoSmallImageTest(
1061 false, false, -1, kSignatureGenerated, true, kSourceMinorPayloadVersion);
1062 }
1063
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedShellTest)1064 TEST_F(DeltaPerformerIntegrationTest,
1065 RunAsRootSmallImageSignGeneratedShellTest) {
1066 DoSmallImageTest(false,
1067 false,
1068 -1,
1069 kSignatureGeneratedShell,
1070 false,
1071 kSourceMinorPayloadVersion);
1072 }
1073
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedShellECKeyTest)1074 TEST_F(DeltaPerformerIntegrationTest,
1075 RunAsRootSmallImageSignGeneratedShellECKeyTest) {
1076 DoSmallImageTest(false,
1077 false,
1078 -1,
1079 kSignatureGeneratedShellECKey,
1080 false,
1081 kSourceMinorPayloadVersion);
1082 }
1083
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedShellBadKeyTest)1084 TEST_F(DeltaPerformerIntegrationTest,
1085 RunAsRootSmallImageSignGeneratedShellBadKeyTest) {
1086 DoSmallImageTest(false,
1087 false,
1088 -1,
1089 kSignatureGeneratedShellBadKey,
1090 false,
1091 kSourceMinorPayloadVersion);
1092 }
1093
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedShellRotateCl1Test)1094 TEST_F(DeltaPerformerIntegrationTest,
1095 RunAsRootSmallImageSignGeneratedShellRotateCl1Test) {
1096 DoSmallImageTest(false,
1097 false,
1098 -1,
1099 kSignatureGeneratedShellRotateCl1,
1100 false,
1101 kSourceMinorPayloadVersion);
1102 }
1103
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSignGeneratedShellRotateCl2Test)1104 TEST_F(DeltaPerformerIntegrationTest,
1105 RunAsRootSmallImageSignGeneratedShellRotateCl2Test) {
1106 DoSmallImageTest(false,
1107 false,
1108 -1,
1109 kSignatureGeneratedShellRotateCl2,
1110 false,
1111 kSourceMinorPayloadVersion);
1112 }
1113
TEST_F(DeltaPerformerIntegrationTest,RunAsRootSmallImageSourceOpsTest)1114 TEST_F(DeltaPerformerIntegrationTest, RunAsRootSmallImageSourceOpsTest) {
1115 DoSmallImageTest(
1116 false, false, -1, kSignatureGenerator, false, kSourceMinorPayloadVersion);
1117 }
1118
TEST_F(DeltaPerformerIntegrationTest,RunAsRootMandatoryOperationHashMismatchTest)1119 TEST_F(DeltaPerformerIntegrationTest,
1120 RunAsRootMandatoryOperationHashMismatchTest) {
1121 DoOperationHashMismatchTest(kInvalidOperationData, true);
1122 }
1123
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampSuccess)1124 TEST_F(DeltaPerformerIntegrationTest, ValidatePerPartitionTimestampSuccess) {
1125 // The Manifest we are validating.
1126 DeltaArchiveManifest manifest;
1127
1128 fake_hardware_.SetVersion("system", "5");
1129 fake_hardware_.SetVersion("product", "99");
1130 fake_hardware_.SetBuildTimestamp(1);
1131
1132 manifest.set_minor_version(kFullPayloadMinorVersion);
1133 manifest.set_max_timestamp(2);
1134 AddPartition(&manifest, "system", 10);
1135 AddPartition(&manifest, "product", 100);
1136
1137 RunManifestValidation(
1138 manifest, kMaxSupportedMajorPayloadVersion, ErrorCode::kSuccess);
1139 }
1140
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampFailure)1141 TEST_F(DeltaPerformerIntegrationTest, ValidatePerPartitionTimestampFailure) {
1142 // The Manifest we are validating.
1143 DeltaArchiveManifest manifest;
1144
1145 fake_hardware_.SetVersion("system", "5");
1146 fake_hardware_.SetVersion("product", "99");
1147 fake_hardware_.SetBuildTimestamp(1);
1148
1149 manifest.set_minor_version(kFullPayloadMinorVersion);
1150 manifest.set_max_timestamp(2);
1151 AddPartition(&manifest, "system", 10);
1152 AddPartition(&manifest, "product", 98);
1153
1154 RunManifestValidation(manifest,
1155 kMaxSupportedMajorPayloadVersion,
1156 ErrorCode::kPayloadTimestampError);
1157 }
1158
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampMissingTimestamp)1159 TEST_F(DeltaPerformerIntegrationTest,
1160 ValidatePerPartitionTimestampMissingTimestamp) {
1161 // The Manifest we are validating.
1162 DeltaArchiveManifest manifest;
1163
1164 fake_hardware_.SetVersion("system", "5");
1165 fake_hardware_.SetVersion("product", "99");
1166 fake_hardware_.SetBuildTimestamp(1);
1167
1168 manifest.set_minor_version(kFullPayloadMinorVersion);
1169 manifest.set_max_timestamp(2);
1170 AddPartition(&manifest, "system", 10);
1171 {
1172 auto& partition = *manifest.add_partitions();
1173 // For complete updates, missing timestamp should not trigger
1174 // timestamp error.
1175 partition.set_partition_name("product");
1176 }
1177
1178 RunManifestValidation(
1179 manifest, kMaxSupportedMajorPayloadVersion, ErrorCode::kSuccess);
1180 }
1181
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampPartialUpdatePass)1182 TEST_F(DeltaPerformerIntegrationTest,
1183 ValidatePerPartitionTimestampPartialUpdatePass) {
1184 fake_hardware_.SetVersion("system", "5");
1185 fake_hardware_.SetVersion("product", "99");
1186
1187 DeltaArchiveManifest manifest;
1188 manifest.set_minor_version(kPartialUpdateMinorPayloadVersion);
1189 manifest.set_partial_update(true);
1190 AddPartition(&manifest, "product", 100);
1191 RunManifestValidation(
1192 manifest, kMaxSupportedMajorPayloadVersion, ErrorCode::kSuccess);
1193 }
1194
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampPartialUpdateDowngrade)1195 TEST_F(DeltaPerformerIntegrationTest,
1196 ValidatePerPartitionTimestampPartialUpdateDowngrade) {
1197 fake_hardware_.SetVersion("system", "5");
1198 fake_hardware_.SetVersion("product", "99");
1199
1200 DeltaArchiveManifest manifest;
1201 manifest.set_minor_version(kPartialUpdateMinorPayloadVersion);
1202 manifest.set_partial_update(true);
1203 AddPartition(&manifest, "product", 98);
1204 RunManifestValidation(manifest,
1205 kMaxSupportedMajorPayloadVersion,
1206 ErrorCode::kPayloadTimestampError);
1207 }
1208
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampPartialUpdateMissingVersion)1209 TEST_F(DeltaPerformerIntegrationTest,
1210 ValidatePerPartitionTimestampPartialUpdateMissingVersion) {
1211 fake_hardware_.SetVersion("system", "5");
1212 fake_hardware_.SetVersion("product", "99");
1213
1214 DeltaArchiveManifest manifest;
1215 manifest.set_minor_version(kPartialUpdateMinorPayloadVersion);
1216 manifest.set_partial_update(true);
1217 {
1218 auto& partition = *manifest.add_partitions();
1219 // For partial updates, missing timestamp should trigger an error
1220 partition.set_partition_name("product");
1221 // has_version() == false.
1222 }
1223 RunManifestValidation(manifest,
1224 kMaxSupportedMajorPayloadVersion,
1225 ErrorCode::kDownloadManifestParseError);
1226 }
1227
TEST_F(DeltaPerformerIntegrationTest,ValidatePerPartitionTimestampPartialUpdateEmptyVersion)1228 TEST_F(DeltaPerformerIntegrationTest,
1229 ValidatePerPartitionTimestampPartialUpdateEmptyVersion) {
1230 fake_hardware_.SetVersion("system", "5");
1231 fake_hardware_.SetVersion("product", "99");
1232
1233 DeltaArchiveManifest manifest;
1234 manifest.set_minor_version(kPartialUpdateMinorPayloadVersion);
1235 manifest.set_partial_update(true);
1236 {
1237 auto& partition = *manifest.add_partitions();
1238 // For partial updates, invalid timestamp should trigger an error
1239 partition.set_partition_name("product");
1240 partition.set_version("something");
1241 }
1242 RunManifestValidation(manifest,
1243 kMaxSupportedMajorPayloadVersion,
1244 ErrorCode::kDownloadManifestParseError);
1245 }
1246
1247 } // namespace chromeos_update_engine
1248