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 <inttypes.h>
20#include <sys/mount.h>
21
22#include <algorithm>
23#include <string>
24#include <vector>
25
26#include <base/files/file_path.h>
27#include <base/files/file_util.h>
28#include <base/strings/string_util.h>
29#include <base/strings/stringprintf.h>
30#include <google/protobuf/repeated_field.h>
31#include <gtest/gtest.h>
32
33#include "update_engine/common/constants.h"
34#include "update_engine/common/fake_boot_control.h"
35#include "update_engine/common/fake_hardware.h"
36#include "update_engine/common/mock_prefs.h"
37#include "update_engine/common/test_utils.h"
38#include "update_engine/common/utils.h"
39#include "update_engine/payload_consumer/mock_download_action.h"
40#include "update_engine/payload_consumer/payload_constants.h"
41#include "update_engine/payload_consumer/payload_verifier.h"
42#include "update_engine/payload_generator/delta_diff_generator.h"
43#include "update_engine/payload_generator/payload_signer.h"
44#include "update_engine/update_metadata.pb.h"
45
46namespace chromeos_update_engine {
47
48using std::string;
49using std::vector;
50using test_utils::ScopedLoopMounter;
51using test_utils::System;
52using test_utils::kRandomString;
53using testing::Return;
54using testing::_;
55
56extern const char* kUnittestPrivateKeyPath;
57extern const char* kUnittestPublicKeyPath;
58extern const char* kUnittestPrivateKey2Path;
59extern const char* kUnittestPublicKey2Path;
60
61static const uint32_t kDefaultKernelSize = 4096;  // Something small for a test
62static const uint8_t kNewData[] = {'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
63                                   'n', 'e', 'w', ' ', 'd', 'a', 't', 'a', '.'};
64
65namespace {
66struct DeltaState {
67  string a_img;
68  string b_img;
69  string result_img;
70  size_t image_size;
71
72  string delta_path;
73  uint64_t metadata_size;
74
75  string old_kernel;
76  brillo::Blob old_kernel_data;
77
78  string new_kernel;
79  brillo::Blob new_kernel_data;
80
81  string result_kernel;
82  brillo::Blob result_kernel_data;
83  size_t kernel_size;
84
85  // The InstallPlan referenced by the DeltaPerformer. This needs to outlive
86  // the DeltaPerformer.
87  InstallPlan install_plan;
88
89  // The in-memory copy of delta file.
90  brillo::Blob delta;
91
92  // Mock and fake instances used by the delta performer.
93  FakeBootControl fake_boot_control_;
94  FakeHardware fake_hardware_;
95  MockDownloadActionDelegate mock_delegate_;
96};
97
98enum SignatureTest {
99  kSignatureNone,  // No payload signing.
100  kSignatureGenerator,  // Sign the payload at generation time.
101  kSignatureGenerated,  // Sign the payload after it's generated.
102  kSignatureGeneratedPlaceholder,  // Insert placeholder signatures, then real.
103  kSignatureGeneratedPlaceholderMismatch,  // Insert a wrong sized placeholder.
104  kSignatureGeneratedShell,  // Sign the generated payload through shell cmds.
105  kSignatureGeneratedShellBadKey,  // Sign with a bad key through shell cmds.
106  kSignatureGeneratedShellRotateCl1,  // Rotate key, test client v1
107  kSignatureGeneratedShellRotateCl2,  // Rotate key, test client v2
108};
109
110enum OperationHashTest {
111  kInvalidOperationData,
112  kValidOperationData,
113};
114
115}  // namespace
116
117class DeltaPerformerIntegrationTest : public ::testing::Test {
118 public:
119  static void SetSupportedVersion(DeltaPerformer* performer,
120                                  uint64_t minor_version) {
121    performer->supported_minor_version_ = minor_version;
122  }
123};
124
125static void CompareFilesByBlock(const string& a_file, const string& b_file,
126                                size_t image_size) {
127  EXPECT_EQ(0U, image_size % kBlockSize);
128
129  brillo::Blob a_data, b_data;
130  EXPECT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file;
131  EXPECT_TRUE(utils::ReadFile(b_file, &b_data)) << "file failed: " << b_file;
132
133  EXPECT_GE(a_data.size(), image_size);
134  EXPECT_GE(b_data.size(), image_size);
135  for (size_t i = 0; i < image_size; i += kBlockSize) {
136    EXPECT_EQ(0U, i % kBlockSize);
137    brillo::Blob a_sub(&a_data[i], &a_data[i + kBlockSize]);
138    brillo::Blob b_sub(&b_data[i], &b_data[i + kBlockSize]);
139    EXPECT_TRUE(a_sub == b_sub) << "Block " << (i/kBlockSize) << " differs";
140  }
141  if (::testing::Test::HasNonfatalFailure()) {
142    LOG(INFO) << "Compared filesystems with size " << image_size
143              << ", partition A " << a_file << " size: " << a_data.size()
144              << ", partition B " << b_file << " size: " << b_data.size();
145  }
146}
147
148static bool WriteSparseFile(const string& path, off_t size) {
149  int fd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
150  TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
151  ScopedFdCloser fd_closer(&fd);
152  off_t rc = lseek(fd, size + 1, SEEK_SET);
153  TEST_AND_RETURN_FALSE_ERRNO(rc != static_cast<off_t>(-1));
154  int return_code = ftruncate(fd, size);
155  TEST_AND_RETURN_FALSE_ERRNO(return_code == 0);
156  return true;
157}
158
159static size_t GetSignatureSize(const string& private_key_path) {
160  const brillo::Blob data(1, 'x');
161  brillo::Blob hash;
162  EXPECT_TRUE(HashCalculator::RawHashOfData(data, &hash));
163  brillo::Blob signature;
164  EXPECT_TRUE(PayloadSigner::SignHash(hash,
165                                      private_key_path,
166                                      &signature));
167  return signature.size();
168}
169
170static bool InsertSignaturePlaceholder(int signature_size,
171                                       const string& payload_path,
172                                       uint64_t* out_metadata_size) {
173  vector<brillo::Blob> signatures;
174  signatures.push_back(brillo::Blob(signature_size, 0));
175
176  return PayloadSigner::AddSignatureToPayload(
177      payload_path,
178      signatures,
179      {},
180      payload_path,
181      out_metadata_size);
182}
183
184static void SignGeneratedPayload(const string& payload_path,
185                                 uint64_t* out_metadata_size) {
186  int signature_size = GetSignatureSize(kUnittestPrivateKeyPath);
187  brillo::Blob hash;
188  ASSERT_TRUE(PayloadSigner::HashPayloadForSigning(
189      payload_path,
190      vector<int>(1, signature_size),
191      &hash,
192      nullptr));
193  brillo::Blob signature;
194  ASSERT_TRUE(PayloadSigner::SignHash(hash,
195                                      kUnittestPrivateKeyPath,
196                                      &signature));
197  ASSERT_TRUE(PayloadSigner::AddSignatureToPayload(
198      payload_path,
199      vector<brillo::Blob>(1, signature),
200      {},
201      payload_path,
202      out_metadata_size));
203  EXPECT_TRUE(PayloadSigner::VerifySignedPayload(
204      payload_path,
205      kUnittestPublicKeyPath));
206}
207
208static void SignGeneratedShellPayload(SignatureTest signature_test,
209                                      const string& payload_path) {
210  string private_key_path = kUnittestPrivateKeyPath;
211  if (signature_test == kSignatureGeneratedShellBadKey) {
212    ASSERT_TRUE(utils::MakeTempFile("key.XXXXXX",
213                                    &private_key_path,
214                                    nullptr));
215  } else {
216    ASSERT_TRUE(signature_test == kSignatureGeneratedShell ||
217                signature_test == kSignatureGeneratedShellRotateCl1 ||
218                signature_test == kSignatureGeneratedShellRotateCl2);
219  }
220  ScopedPathUnlinker key_unlinker(private_key_path);
221  key_unlinker.set_should_remove(signature_test ==
222                                 kSignatureGeneratedShellBadKey);
223  // Generates a new private key that will not match the public key.
224  if (signature_test == kSignatureGeneratedShellBadKey) {
225    LOG(INFO) << "Generating a mismatched private key.";
226    ASSERT_EQ(0, System(base::StringPrintf(
227        "openssl genrsa -out %s 2048", private_key_path.c_str())));
228  }
229  int signature_size = GetSignatureSize(private_key_path);
230  string hash_file;
231  ASSERT_TRUE(utils::MakeTempFile("hash.XXXXXX", &hash_file, nullptr));
232  ScopedPathUnlinker hash_unlinker(hash_file);
233  string signature_size_string;
234  if (signature_test == kSignatureGeneratedShellRotateCl1 ||
235      signature_test == kSignatureGeneratedShellRotateCl2)
236    signature_size_string = base::StringPrintf("%d:%d",
237                                               signature_size, signature_size);
238  else
239    signature_size_string = base::StringPrintf("%d", signature_size);
240  ASSERT_EQ(0,
241            System(base::StringPrintf(
242                "./delta_generator -in_file=%s -signature_size=%s "
243                "-out_hash_file=%s",
244                payload_path.c_str(),
245                signature_size_string.c_str(),
246                hash_file.c_str())));
247
248  // Pad the hash
249  brillo::Blob hash;
250  ASSERT_TRUE(utils::ReadFile(hash_file, &hash));
251  ASSERT_TRUE(PayloadVerifier::PadRSA2048SHA256Hash(&hash));
252  ASSERT_TRUE(test_utils::WriteFileVector(hash_file, hash));
253
254  string sig_file;
255  ASSERT_TRUE(utils::MakeTempFile("signature.XXXXXX", &sig_file, nullptr));
256  ScopedPathUnlinker sig_unlinker(sig_file);
257  ASSERT_EQ(0,
258            System(base::StringPrintf(
259                "openssl rsautl -raw -sign -inkey %s -in %s -out %s",
260                private_key_path.c_str(),
261                hash_file.c_str(),
262                sig_file.c_str())));
263  string sig_file2;
264  ASSERT_TRUE(utils::MakeTempFile("signature.XXXXXX", &sig_file2, nullptr));
265  ScopedPathUnlinker sig2_unlinker(sig_file2);
266  if (signature_test == kSignatureGeneratedShellRotateCl1 ||
267      signature_test == kSignatureGeneratedShellRotateCl2) {
268    ASSERT_EQ(0,
269              System(base::StringPrintf(
270                  "openssl rsautl -raw -sign -inkey %s -in %s -out %s",
271                  kUnittestPrivateKey2Path,
272                  hash_file.c_str(),
273                  sig_file2.c_str())));
274    // Append second sig file to first path
275    sig_file += ":" + sig_file2;
276  }
277
278  ASSERT_EQ(0,
279            System(base::StringPrintf(
280                "./delta_generator -in_file=%s -signature_file=%s "
281                "-out_file=%s",
282                payload_path.c_str(),
283                sig_file.c_str(),
284                payload_path.c_str())));
285  int verify_result =
286      System(base::StringPrintf(
287          "./delta_generator -in_file=%s -public_key=%s -public_key_version=%d",
288          payload_path.c_str(),
289          signature_test == kSignatureGeneratedShellRotateCl2 ?
290          kUnittestPublicKey2Path : kUnittestPublicKeyPath,
291          signature_test == kSignatureGeneratedShellRotateCl2 ? 2 : 1));
292  if (signature_test == kSignatureGeneratedShellBadKey) {
293    ASSERT_NE(0, verify_result);
294  } else {
295    ASSERT_EQ(0, verify_result);
296  }
297}
298
299static void GenerateDeltaFile(bool full_kernel,
300                              bool full_rootfs,
301                              bool noop,
302                              ssize_t chunk_size,
303                              SignatureTest signature_test,
304                              DeltaState *state,
305                              uint32_t minor_version) {
306  EXPECT_TRUE(utils::MakeTempFile("a_img.XXXXXX", &state->a_img, nullptr));
307  EXPECT_TRUE(utils::MakeTempFile("b_img.XXXXXX", &state->b_img, nullptr));
308
309  // result_img is used in minor version 2. Instead of applying the update
310  // in-place on A, we apply it to a new image, result_img.
311  EXPECT_TRUE(
312      utils::MakeTempFile("result_img.XXXXXX", &state->result_img, nullptr));
313  test_utils::CreateExtImageAtPath(state->a_img, nullptr);
314
315  state->image_size = utils::FileSize(state->a_img);
316
317  // Create ImageInfo A & B
318  ImageInfo old_image_info;
319  ImageInfo new_image_info;
320
321  if (!full_rootfs) {
322    old_image_info.set_channel("src-channel");
323    old_image_info.set_board("src-board");
324    old_image_info.set_version("src-version");
325    old_image_info.set_key("src-key");
326    old_image_info.set_build_channel("src-build-channel");
327    old_image_info.set_build_version("src-build-version");
328  }
329
330  new_image_info.set_channel("test-channel");
331  new_image_info.set_board("test-board");
332  new_image_info.set_version("test-version");
333  new_image_info.set_key("test-key");
334  new_image_info.set_build_channel("test-build-channel");
335  new_image_info.set_build_version("test-build-version");
336
337  // Make some changes to the A image.
338  {
339    string a_mnt;
340    ScopedLoopMounter b_mounter(state->a_img, &a_mnt, 0);
341
342    brillo::Blob hardtocompress;
343    while (hardtocompress.size() < 3 * kBlockSize) {
344      hardtocompress.insert(hardtocompress.end(),
345                            std::begin(kRandomString), std::end(kRandomString));
346    }
347    EXPECT_TRUE(utils::WriteFile(base::StringPrintf("%s/hardtocompress",
348                                                    a_mnt.c_str()).c_str(),
349                                 hardtocompress.data(),
350                                 hardtocompress.size()));
351
352    brillo::Blob zeros(16 * 1024, 0);
353    EXPECT_EQ(static_cast<int>(zeros.size()),
354              base::WriteFile(base::FilePath(base::StringPrintf(
355                                  "%s/move-to-sparse", a_mnt.c_str())),
356                              reinterpret_cast<const char*>(zeros.data()),
357                              zeros.size()));
358
359    EXPECT_TRUE(
360        WriteSparseFile(base::StringPrintf("%s/move-from-sparse",
361                                           a_mnt.c_str()), 16 * 1024));
362
363    EXPECT_EQ(0,
364              System(base::StringPrintf("dd if=/dev/zero of=%s/move-semi-sparse"
365                                        " bs=1 seek=4096 count=1 status=none",
366                                        a_mnt.c_str()).c_str()));
367
368    // Write 1 MiB of 0xff to try to catch the case where writing a bsdiff
369    // patch fails to zero out the final block.
370    brillo::Blob ones(1024 * 1024, 0xff);
371    EXPECT_TRUE(utils::WriteFile(base::StringPrintf("%s/ones",
372                                                    a_mnt.c_str()).c_str(),
373                                 ones.data(),
374                                 ones.size()));
375  }
376
377  if (noop) {
378    EXPECT_TRUE(base::CopyFile(base::FilePath(state->a_img),
379                               base::FilePath(state->b_img)));
380    old_image_info = new_image_info;
381  } else {
382    if (minor_version == kSourceMinorPayloadVersion) {
383      // Create a result image with image_size bytes of garbage.
384      brillo::Blob ones(state->image_size, 0xff);
385      EXPECT_TRUE(utils::WriteFile(state->result_img.c_str(),
386                                   ones.data(),
387                                   ones.size()));
388      EXPECT_EQ(utils::FileSize(state->a_img),
389                utils::FileSize(state->result_img));
390    }
391
392    test_utils::CreateExtImageAtPath(state->b_img, nullptr);
393
394    // Make some changes to the B image.
395    string b_mnt;
396    ScopedLoopMounter b_mounter(state->b_img, &b_mnt, 0);
397
398    EXPECT_EQ(0, System(base::StringPrintf("cp %s/hello %s/hello2",
399                                           b_mnt.c_str(),
400                                           b_mnt.c_str()).c_str()));
401    EXPECT_EQ(0, System(base::StringPrintf("rm %s/hello",
402                                           b_mnt.c_str()).c_str()));
403    EXPECT_EQ(0, System(base::StringPrintf("mv %s/hello2 %s/hello",
404                                           b_mnt.c_str(),
405                                           b_mnt.c_str()).c_str()));
406    EXPECT_EQ(0, System(base::StringPrintf("echo foo > %s/foo",
407                                           b_mnt.c_str()).c_str()));
408    EXPECT_EQ(0, System(base::StringPrintf("touch %s/emptyfile",
409                                           b_mnt.c_str()).c_str()));
410    EXPECT_TRUE(WriteSparseFile(base::StringPrintf("%s/fullsparse",
411                                                   b_mnt.c_str()),
412                                                   1024 * 1024));
413
414    EXPECT_TRUE(
415        WriteSparseFile(base::StringPrintf("%s/move-to-sparse", b_mnt.c_str()),
416                        16 * 1024));
417
418    brillo::Blob zeros(16 * 1024, 0);
419    EXPECT_EQ(static_cast<int>(zeros.size()),
420              base::WriteFile(base::FilePath(base::StringPrintf(
421                                  "%s/move-from-sparse", b_mnt.c_str())),
422                              reinterpret_cast<const char*>(zeros.data()),
423                              zeros.size()));
424
425    EXPECT_EQ(0, System(base::StringPrintf("dd if=/dev/zero "
426                                           "of=%s/move-semi-sparse "
427                                           "bs=1 seek=4096 count=1 status=none",
428                                           b_mnt.c_str()).c_str()));
429
430    EXPECT_EQ(0, System(base::StringPrintf("dd if=/dev/zero "
431                                           "of=%s/partsparse bs=1 "
432                                           "seek=4096 count=1 status=none",
433                                           b_mnt.c_str()).c_str()));
434    EXPECT_EQ(0, System(base::StringPrintf("cp %s/srchardlink0 %s/tmp && "
435                                           "mv %s/tmp %s/srchardlink1",
436                                           b_mnt.c_str(),
437                                           b_mnt.c_str(),
438                                           b_mnt.c_str(),
439                                           b_mnt.c_str()).c_str()));
440    EXPECT_EQ(0, System(
441        base::StringPrintf("rm %s/boguslink && echo foobar > %s/boguslink",
442                           b_mnt.c_str(), b_mnt.c_str()).c_str()));
443
444    brillo::Blob hardtocompress;
445    while (hardtocompress.size() < 3 * kBlockSize) {
446      hardtocompress.insert(hardtocompress.end(),
447                            std::begin(kRandomString), std::end(kRandomString));
448    }
449    EXPECT_TRUE(utils::WriteFile(base::StringPrintf("%s/hardtocompress",
450                                              b_mnt.c_str()).c_str(),
451                                 hardtocompress.data(),
452                                 hardtocompress.size()));
453  }
454
455  string old_kernel;
456  EXPECT_TRUE(utils::MakeTempFile("old_kernel.XXXXXX",
457                                  &state->old_kernel,
458                                  nullptr));
459
460  string new_kernel;
461  EXPECT_TRUE(utils::MakeTempFile("new_kernel.XXXXXX",
462                                  &state->new_kernel,
463                                  nullptr));
464
465  string result_kernel;
466  EXPECT_TRUE(utils::MakeTempFile("result_kernel.XXXXXX",
467                                  &state->result_kernel,
468                                  nullptr));
469
470  state->kernel_size = kDefaultKernelSize;
471  state->old_kernel_data.resize(kDefaultKernelSize);
472  state->new_kernel_data.resize(state->old_kernel_data.size());
473  state->result_kernel_data.resize(state->old_kernel_data.size());
474  test_utils::FillWithData(&state->old_kernel_data);
475  test_utils::FillWithData(&state->new_kernel_data);
476  test_utils::FillWithData(&state->result_kernel_data);
477
478  // change the new kernel data
479  std::copy(std::begin(kNewData), std::end(kNewData),
480            state->new_kernel_data.begin());
481
482  if (noop) {
483    state->old_kernel_data = state->new_kernel_data;
484  }
485
486  // Write kernels to disk
487  EXPECT_TRUE(utils::WriteFile(state->old_kernel.c_str(),
488                               state->old_kernel_data.data(),
489                               state->old_kernel_data.size()));
490  EXPECT_TRUE(utils::WriteFile(state->new_kernel.c_str(),
491                               state->new_kernel_data.data(),
492                               state->new_kernel_data.size()));
493  EXPECT_TRUE(utils::WriteFile(state->result_kernel.c_str(),
494                               state->result_kernel_data.data(),
495                               state->result_kernel_data.size()));
496
497  EXPECT_TRUE(utils::MakeTempFile("delta.XXXXXX",
498                                  &state->delta_path,
499                                  nullptr));
500  LOG(INFO) << "delta path: " << state->delta_path;
501  {
502    const string private_key =
503        signature_test == kSignatureGenerator ? kUnittestPrivateKeyPath : "";
504
505    PayloadGenerationConfig payload_config;
506    payload_config.is_delta = !full_rootfs;
507    payload_config.hard_chunk_size = chunk_size;
508    payload_config.rootfs_partition_size = kRootFSPartitionSize;
509    payload_config.version.major = kChromeOSMajorPayloadVersion;
510    payload_config.version.minor = minor_version;
511    if (!full_rootfs) {
512      payload_config.source.partitions.emplace_back(kLegacyPartitionNameRoot);
513      payload_config.source.partitions.emplace_back(kLegacyPartitionNameKernel);
514      payload_config.source.partitions.front().path = state->a_img;
515      if (!full_kernel)
516        payload_config.source.partitions.back().path = state->old_kernel;
517      payload_config.source.image_info = old_image_info;
518      EXPECT_TRUE(payload_config.source.LoadImageSize());
519      for (PartitionConfig& part : payload_config.source.partitions)
520        EXPECT_TRUE(part.OpenFilesystem());
521    } else {
522      if (payload_config.hard_chunk_size == -1)
523        // Use 1 MiB chunk size for the full unittests.
524        payload_config.hard_chunk_size = 1024 * 1024;
525    }
526    payload_config.target.partitions.emplace_back(kLegacyPartitionNameRoot);
527    payload_config.target.partitions.back().path = state->b_img;
528    payload_config.target.partitions.emplace_back(kLegacyPartitionNameKernel);
529    payload_config.target.partitions.back().path = state->new_kernel;
530    payload_config.target.image_info = new_image_info;
531    EXPECT_TRUE(payload_config.target.LoadImageSize());
532    for (PartitionConfig& part : payload_config.target.partitions)
533      EXPECT_TRUE(part.OpenFilesystem());
534
535    EXPECT_TRUE(payload_config.Validate());
536    EXPECT_TRUE(
537        GenerateUpdatePayloadFile(
538            payload_config,
539            state->delta_path,
540            private_key,
541            &state->metadata_size));
542  }
543  // Extend the "partitions" holding the file system a bit.
544  EXPECT_EQ(0, HANDLE_EINTR(truncate(state->a_img.c_str(),
545                                     state->image_size + 1024 * 1024)));
546  EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
547            utils::FileSize(state->a_img));
548  EXPECT_EQ(0, HANDLE_EINTR(truncate(state->b_img.c_str(),
549                                     state->image_size + 1024 * 1024)));
550  EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
551            utils::FileSize(state->b_img));
552
553  if (signature_test == kSignatureGeneratedPlaceholder ||
554      signature_test == kSignatureGeneratedPlaceholderMismatch) {
555    int signature_size = GetSignatureSize(kUnittestPrivateKeyPath);
556    LOG(INFO) << "Inserting placeholder signature.";
557    ASSERT_TRUE(InsertSignaturePlaceholder(signature_size, state->delta_path,
558                                           &state->metadata_size));
559
560    if (signature_test == kSignatureGeneratedPlaceholderMismatch) {
561      signature_size -= 1;
562      LOG(INFO) << "Inserting mismatched placeholder signature.";
563      ASSERT_FALSE(InsertSignaturePlaceholder(signature_size, state->delta_path,
564                                              &state->metadata_size));
565      return;
566    }
567  }
568
569  if (signature_test == kSignatureGenerated ||
570      signature_test == kSignatureGeneratedPlaceholder ||
571      signature_test == kSignatureGeneratedPlaceholderMismatch) {
572    // Generate the signed payload and update the metadata size in state to
573    // reflect the new size after adding the signature operation to the
574    // manifest.
575    LOG(INFO) << "Signing payload.";
576    SignGeneratedPayload(state->delta_path, &state->metadata_size);
577  } else if (signature_test == kSignatureGeneratedShell ||
578             signature_test == kSignatureGeneratedShellBadKey ||
579             signature_test == kSignatureGeneratedShellRotateCl1 ||
580             signature_test == kSignatureGeneratedShellRotateCl2) {
581    SignGeneratedShellPayload(signature_test, state->delta_path);
582  }
583}
584
585static void ApplyDeltaFile(bool full_kernel, bool full_rootfs, bool noop,
586                           SignatureTest signature_test, DeltaState* state,
587                           bool hash_checks_mandatory,
588                           OperationHashTest op_hash_test,
589                           DeltaPerformer** performer,
590                           uint32_t minor_version) {
591  // Check the metadata.
592  {
593    DeltaArchiveManifest manifest;
594    EXPECT_TRUE(PayloadSigner::LoadPayloadMetadata(state->delta_path,
595                                                   nullptr,
596                                                   &manifest,
597                                                   nullptr,
598                                                   &state->metadata_size,
599                                                   nullptr));
600    LOG(INFO) << "Metadata size: " << state->metadata_size;
601    EXPECT_TRUE(utils::ReadFile(state->delta_path, &state->delta));
602
603    if (signature_test == kSignatureNone) {
604      EXPECT_FALSE(manifest.has_signatures_offset());
605      EXPECT_FALSE(manifest.has_signatures_size());
606    } else {
607      EXPECT_TRUE(manifest.has_signatures_offset());
608      EXPECT_TRUE(manifest.has_signatures_size());
609      Signatures sigs_message;
610      EXPECT_TRUE(sigs_message.ParseFromArray(
611          &state->delta[state->metadata_size + manifest.signatures_offset()],
612          manifest.signatures_size()));
613      if (signature_test == kSignatureGeneratedShellRotateCl1 ||
614          signature_test == kSignatureGeneratedShellRotateCl2)
615        EXPECT_EQ(2, sigs_message.signatures_size());
616      else
617        EXPECT_EQ(1, sigs_message.signatures_size());
618      const Signatures_Signature& signature = sigs_message.signatures(0);
619      EXPECT_EQ(1U, signature.version());
620
621      uint64_t expected_sig_data_length = 0;
622      vector<string> key_paths{kUnittestPrivateKeyPath};
623      if (signature_test == kSignatureGeneratedShellRotateCl1 ||
624          signature_test == kSignatureGeneratedShellRotateCl2) {
625        key_paths.push_back(kUnittestPrivateKey2Path);
626      }
627      EXPECT_TRUE(PayloadSigner::SignatureBlobLength(
628          key_paths,
629          &expected_sig_data_length));
630      EXPECT_EQ(expected_sig_data_length, manifest.signatures_size());
631      EXPECT_FALSE(signature.data().empty());
632    }
633
634    if (noop) {
635      EXPECT_EQ(0, manifest.install_operations_size());
636      EXPECT_EQ(1, manifest.kernel_install_operations_size());
637    }
638
639    if (full_kernel) {
640      EXPECT_FALSE(manifest.has_old_kernel_info());
641    } else {
642      EXPECT_EQ(state->old_kernel_data.size(),
643                manifest.old_kernel_info().size());
644      EXPECT_FALSE(manifest.old_kernel_info().hash().empty());
645    }
646
647    EXPECT_EQ(manifest.new_image_info().channel(), "test-channel");
648    EXPECT_EQ(manifest.new_image_info().board(), "test-board");
649    EXPECT_EQ(manifest.new_image_info().version(), "test-version");
650    EXPECT_EQ(manifest.new_image_info().key(), "test-key");
651    EXPECT_EQ(manifest.new_image_info().build_channel(), "test-build-channel");
652    EXPECT_EQ(manifest.new_image_info().build_version(), "test-build-version");
653
654    if (!full_rootfs) {
655      if (noop) {
656        EXPECT_EQ(manifest.old_image_info().channel(), "test-channel");
657        EXPECT_EQ(manifest.old_image_info().board(), "test-board");
658        EXPECT_EQ(manifest.old_image_info().version(), "test-version");
659        EXPECT_EQ(manifest.old_image_info().key(), "test-key");
660        EXPECT_EQ(manifest.old_image_info().build_channel(),
661                  "test-build-channel");
662        EXPECT_EQ(manifest.old_image_info().build_version(),
663                  "test-build-version");
664      } else {
665        EXPECT_EQ(manifest.old_image_info().channel(), "src-channel");
666        EXPECT_EQ(manifest.old_image_info().board(), "src-board");
667        EXPECT_EQ(manifest.old_image_info().version(), "src-version");
668        EXPECT_EQ(manifest.old_image_info().key(), "src-key");
669        EXPECT_EQ(manifest.old_image_info().build_channel(),
670                  "src-build-channel");
671        EXPECT_EQ(manifest.old_image_info().build_version(),
672                  "src-build-version");
673      }
674    }
675
676
677    if (full_rootfs) {
678      EXPECT_FALSE(manifest.has_old_rootfs_info());
679      EXPECT_FALSE(manifest.has_old_image_info());
680      EXPECT_TRUE(manifest.has_new_image_info());
681    } else {
682      EXPECT_EQ(state->image_size, manifest.old_rootfs_info().size());
683      EXPECT_FALSE(manifest.old_rootfs_info().hash().empty());
684    }
685
686    EXPECT_EQ(state->new_kernel_data.size(), manifest.new_kernel_info().size());
687    EXPECT_EQ(state->image_size, manifest.new_rootfs_info().size());
688
689    EXPECT_FALSE(manifest.new_kernel_info().hash().empty());
690    EXPECT_FALSE(manifest.new_rootfs_info().hash().empty());
691  }
692
693  MockPrefs prefs;
694  EXPECT_CALL(prefs, SetInt64(kPrefsManifestMetadataSize,
695                              state->metadata_size)).WillOnce(Return(true));
696  EXPECT_CALL(prefs, SetInt64(kPrefsManifestSignatureSize, 0))
697      .WillOnce(Return(true));
698  EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextOperation, _))
699      .WillRepeatedly(Return(true));
700  EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextOperation, _))
701      .WillOnce(Return(false));
702  EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataOffset, _))
703      .WillRepeatedly(Return(true));
704  EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataLength, _))
705      .WillRepeatedly(Return(true));
706  EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSHA256Context, _))
707      .WillRepeatedly(Return(true));
708  EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignedSHA256Context, _))
709      .WillRepeatedly(Return(true));
710  if (op_hash_test == kValidOperationData && signature_test != kSignatureNone) {
711    EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignatureBlob, _))
712        .WillOnce(Return(true));
713  }
714
715  EXPECT_CALL(state->mock_delegate_, ShouldCancel(_))
716      .WillRepeatedly(Return(false));
717
718  // Update the A image in place.
719  InstallPlan* install_plan = &state->install_plan;
720  install_plan->hash_checks_mandatory = hash_checks_mandatory;
721  install_plan->metadata_size = state->metadata_size;
722  install_plan->payload_type = (full_kernel && full_rootfs)
723                                   ? InstallPayloadType::kFull
724                                   : InstallPayloadType::kDelta;
725  install_plan->source_slot = 0;
726  install_plan->target_slot = 1;
727
728  InstallPlan::Partition root_part;
729  root_part.name = kLegacyPartitionNameRoot;
730
731  InstallPlan::Partition kernel_part;
732  kernel_part.name = kLegacyPartitionNameKernel;
733
734  LOG(INFO) << "Setting payload metadata size in Omaha  = "
735            << state->metadata_size;
736  ASSERT_TRUE(PayloadSigner::GetMetadataSignature(
737      state->delta.data(),
738      state->metadata_size,
739      kUnittestPrivateKeyPath,
740      &install_plan->metadata_signature));
741  EXPECT_FALSE(install_plan->metadata_signature.empty());
742
743  *performer = new DeltaPerformer(&prefs,
744                                  &state->fake_boot_control_,
745                                  &state->fake_hardware_,
746                                  &state->mock_delegate_,
747                                  install_plan);
748  EXPECT_TRUE(utils::FileExists(kUnittestPublicKeyPath));
749  (*performer)->set_public_key_path(kUnittestPublicKeyPath);
750  DeltaPerformerIntegrationTest::SetSupportedVersion(*performer, minor_version);
751
752  EXPECT_EQ(static_cast<off_t>(state->image_size),
753            HashCalculator::RawHashOfFile(
754                state->a_img,
755                state->image_size,
756                &root_part.source_hash));
757  EXPECT_TRUE(HashCalculator::RawHashOfData(
758                  state->old_kernel_data,
759                  &kernel_part.source_hash));
760
761  // This partitions are normally filed by the FilesystemVerifierAction with
762  // the source hashes used for deltas.
763  install_plan->partitions = {root_part, kernel_part};
764
765  // With minor version 2, we want the target to be the new image, result_img,
766  // but with version 1, we want to update A in place.
767  string target_root, target_kernel;
768  if (minor_version == kSourceMinorPayloadVersion) {
769    target_root = state->result_img;
770    target_kernel = state->result_kernel;
771  } else {
772    target_root = state->a_img;
773    target_kernel = state->old_kernel;
774  }
775
776  state->fake_boot_control_.SetPartitionDevice(
777      kLegacyPartitionNameRoot, install_plan->source_slot, state->a_img);
778  state->fake_boot_control_.SetPartitionDevice(
779      kLegacyPartitionNameKernel, install_plan->source_slot, state->old_kernel);
780  state->fake_boot_control_.SetPartitionDevice(
781      kLegacyPartitionNameRoot, install_plan->target_slot, target_root);
782  state->fake_boot_control_.SetPartitionDevice(
783      kLegacyPartitionNameKernel, install_plan->target_slot, target_kernel);
784
785  ErrorCode expected_error, actual_error;
786  bool continue_writing;
787  switch (op_hash_test) {
788    case kInvalidOperationData: {
789      // Muck with some random offset post the metadata size so that
790      // some operation hash will result in a mismatch.
791      int some_offset = state->metadata_size + 300;
792      LOG(INFO) << "Tampered value at offset: " << some_offset;
793      state->delta[some_offset]++;
794      expected_error = ErrorCode::kDownloadOperationHashMismatch;
795      continue_writing = false;
796      break;
797    }
798
799    case kValidOperationData:
800    default:
801      // no change.
802      expected_error = ErrorCode::kSuccess;
803      continue_writing = true;
804      break;
805  }
806
807  // Write at some number of bytes per operation. Arbitrarily chose 5.
808  const size_t kBytesPerWrite = 5;
809  for (size_t i = 0; i < state->delta.size(); i += kBytesPerWrite) {
810    size_t count = std::min(state->delta.size() - i, kBytesPerWrite);
811    bool write_succeeded = ((*performer)->Write(&state->delta[i],
812                                                count,
813                                                &actual_error));
814    // Normally write_succeeded should be true every time and
815    // actual_error should be ErrorCode::kSuccess. If so, continue the loop.
816    // But if we seeded an operation hash error above, then write_succeeded
817    // will be false. The failure may happen at any operation n. So, all
818    // Writes until n-1 should succeed and the nth operation will fail with
819    // actual_error. In this case, we should bail out of the loop because
820    // we cannot proceed applying the delta.
821    if (!write_succeeded) {
822      LOG(INFO) << "Write failed. Checking if it failed with expected error";
823      EXPECT_EQ(expected_error, actual_error);
824      if (!continue_writing) {
825        LOG(INFO) << "Cannot continue writing. Bailing out.";
826        break;
827      }
828    }
829
830    EXPECT_EQ(ErrorCode::kSuccess, actual_error);
831  }
832
833  // If we had continued all the way through, Close should succeed.
834  // Otherwise, it should fail. Check appropriately.
835  bool close_result = (*performer)->Close();
836  if (continue_writing)
837    EXPECT_EQ(0, close_result);
838  else
839    EXPECT_LE(0, close_result);
840}
841
842void VerifyPayloadResult(DeltaPerformer* performer,
843                         DeltaState* state,
844                         ErrorCode expected_result,
845                         uint32_t minor_version) {
846  if (!performer) {
847    EXPECT_TRUE(!"Skipping payload verification since performer is null.");
848    return;
849  }
850
851  int expected_times = (expected_result == ErrorCode::kSuccess) ? 1 : 0;
852  EXPECT_CALL(state->mock_delegate_, DownloadComplete()).Times(expected_times);
853
854  LOG(INFO) << "Verifying payload for expected result "
855            << expected_result;
856  EXPECT_EQ(expected_result, performer->VerifyPayload(
857      HashCalculator::HashOfData(state->delta),
858      state->delta.size()));
859  LOG(INFO) << "Verified payload.";
860
861  if (expected_result != ErrorCode::kSuccess) {
862    // no need to verify new partition if VerifyPayload failed.
863    return;
864  }
865
866  brillo::Blob updated_kernel_partition;
867  if (minor_version == kSourceMinorPayloadVersion) {
868    CompareFilesByBlock(state->result_kernel, state->new_kernel,
869                        state->kernel_size);
870    CompareFilesByBlock(state->result_img, state->b_img,
871                        state->image_size);
872    EXPECT_TRUE(utils::ReadFile(state->result_kernel,
873                                &updated_kernel_partition));
874  } else {
875    CompareFilesByBlock(state->old_kernel, state->new_kernel,
876                        state->kernel_size);
877    CompareFilesByBlock(state->a_img, state->b_img,
878                        state->image_size);
879    EXPECT_TRUE(utils::ReadFile(state->old_kernel, &updated_kernel_partition));
880  }
881
882  ASSERT_GE(updated_kernel_partition.size(), arraysize(kNewData));
883  EXPECT_TRUE(std::equal(std::begin(kNewData), std::end(kNewData),
884                         updated_kernel_partition.begin()));
885
886  const auto& partitions = state->install_plan.partitions;
887  EXPECT_EQ(2U, partitions.size());
888  EXPECT_EQ(kLegacyPartitionNameRoot, partitions[0].name);
889  EXPECT_EQ(kLegacyPartitionNameKernel, partitions[1].name);
890
891  EXPECT_EQ(kDefaultKernelSize, partitions[1].target_size);
892  brillo::Blob expected_new_kernel_hash;
893  EXPECT_TRUE(HashCalculator::RawHashOfData(state->new_kernel_data,
894                                            &expected_new_kernel_hash));
895  EXPECT_EQ(expected_new_kernel_hash, partitions[1].target_hash);
896
897  EXPECT_EQ(state->image_size, partitions[0].target_size);
898  brillo::Blob expected_new_rootfs_hash;
899  EXPECT_EQ(static_cast<off_t>(state->image_size),
900            HashCalculator::RawHashOfFile(state->b_img,
901                                          state->image_size,
902                                          &expected_new_rootfs_hash));
903  EXPECT_EQ(expected_new_rootfs_hash, partitions[0].target_hash);
904}
905
906void VerifyPayload(DeltaPerformer* performer,
907                   DeltaState* state,
908                   SignatureTest signature_test,
909                   uint32_t minor_version) {
910  ErrorCode expected_result = ErrorCode::kSuccess;
911  switch (signature_test) {
912    case kSignatureNone:
913      expected_result = ErrorCode::kSignedDeltaPayloadExpectedError;
914      break;
915    case kSignatureGeneratedShellBadKey:
916      expected_result = ErrorCode::kDownloadPayloadPubKeyVerificationError;
917      break;
918    default: break;  // appease gcc
919  }
920
921  VerifyPayloadResult(performer, state, expected_result, minor_version);
922}
923
924void DoSmallImageTest(bool full_kernel, bool full_rootfs, bool noop,
925                      ssize_t chunk_size,
926                      SignatureTest signature_test,
927                      bool hash_checks_mandatory, uint32_t minor_version) {
928  DeltaState state;
929  DeltaPerformer *performer = nullptr;
930  GenerateDeltaFile(full_kernel, full_rootfs, noop, chunk_size,
931                    signature_test, &state, minor_version);
932
933  ScopedPathUnlinker a_img_unlinker(state.a_img);
934  ScopedPathUnlinker b_img_unlinker(state.b_img);
935  ScopedPathUnlinker new_img_unlinker(state.result_img);
936  ScopedPathUnlinker delta_unlinker(state.delta_path);
937  ScopedPathUnlinker old_kernel_unlinker(state.old_kernel);
938  ScopedPathUnlinker new_kernel_unlinker(state.new_kernel);
939  ScopedPathUnlinker result_kernel_unlinker(state.result_kernel);
940  ApplyDeltaFile(full_kernel, full_rootfs, noop, signature_test,
941                 &state, hash_checks_mandatory, kValidOperationData,
942                 &performer, minor_version);
943  VerifyPayload(performer, &state, signature_test, minor_version);
944  delete performer;
945}
946
947void DoOperationHashMismatchTest(OperationHashTest op_hash_test,
948                                 bool hash_checks_mandatory) {
949  DeltaState state;
950  uint64_t minor_version = kFullPayloadMinorVersion;
951  GenerateDeltaFile(true, true, false, -1, kSignatureGenerated, &state,
952                    minor_version);
953  ScopedPathUnlinker a_img_unlinker(state.a_img);
954  ScopedPathUnlinker b_img_unlinker(state.b_img);
955  ScopedPathUnlinker delta_unlinker(state.delta_path);
956  ScopedPathUnlinker old_kernel_unlinker(state.old_kernel);
957  ScopedPathUnlinker new_kernel_unlinker(state.new_kernel);
958  DeltaPerformer *performer = nullptr;
959  ApplyDeltaFile(true, true, false, kSignatureGenerated, &state,
960                 hash_checks_mandatory, op_hash_test, &performer,
961                 minor_version);
962  delete performer;
963}
964
965
966TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageTest) {
967  DoSmallImageTest(false, false, false, -1, kSignatureGenerator,
968                   false, kInPlaceMinorPayloadVersion);
969}
970
971TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignaturePlaceholderTest) {
972  DoSmallImageTest(false, false, false, -1, kSignatureGeneratedPlaceholder,
973                   false, kInPlaceMinorPayloadVersion);
974}
975
976TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignaturePlaceholderMismatchTest) {
977  DeltaState state;
978  GenerateDeltaFile(false, false, false, -1,
979                    kSignatureGeneratedPlaceholderMismatch, &state,
980                    kInPlaceMinorPayloadVersion);
981}
982
983TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageChunksTest) {
984  DoSmallImageTest(false, false, false, kBlockSize, kSignatureGenerator,
985                   false, kInPlaceMinorPayloadVersion);
986}
987
988TEST(DeltaPerformerIntegrationTest, RunAsRootFullKernelSmallImageTest) {
989  DoSmallImageTest(true, false, false, -1, kSignatureGenerator,
990                   false, kInPlaceMinorPayloadVersion);
991}
992
993TEST(DeltaPerformerIntegrationTest, RunAsRootFullSmallImageTest) {
994  DoSmallImageTest(true, true, false, -1, kSignatureGenerator,
995                   true, kFullPayloadMinorVersion);
996}
997
998TEST(DeltaPerformerIntegrationTest, RunAsRootNoopSmallImageTest) {
999  DoSmallImageTest(false, false, true, -1, kSignatureGenerator,
1000                   false, kInPlaceMinorPayloadVersion);
1001}
1002
1003TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignNoneTest) {
1004  DoSmallImageTest(false, false, false, -1, kSignatureNone,
1005                   false, kInPlaceMinorPayloadVersion);
1006}
1007
1008TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedTest) {
1009  DoSmallImageTest(false, false, false, -1, kSignatureGenerated,
1010                   true, kInPlaceMinorPayloadVersion);
1011}
1012
1013TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedShellTest) {
1014  DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShell,
1015                   false, kInPlaceMinorPayloadVersion);
1016}
1017
1018TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedShellBadKeyTest) {
1019  DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShellBadKey,
1020                   false, kInPlaceMinorPayloadVersion);
1021}
1022
1023TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedShellRotateCl1Test) {
1024  DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShellRotateCl1,
1025                   false, kInPlaceMinorPayloadVersion);
1026}
1027
1028TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedShellRotateCl2Test) {
1029  DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShellRotateCl2,
1030                   false, kInPlaceMinorPayloadVersion);
1031}
1032
1033TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSourceOpsTest) {
1034  DoSmallImageTest(false, false, false, -1, kSignatureGenerator,
1035                   false, kSourceMinorPayloadVersion);
1036}
1037
1038TEST(DeltaPerformerIntegrationTest, RunAsRootMandatoryOperationHashMismatchTest) {
1039  DoOperationHashMismatchTest(kInvalidOperationData, true);
1040}
1041
1042}  // namespace chromeos_update_engine
1043