blob: e064077f65c12f62e06a7b07024f7af5344e7afd [file] [log] [blame]
Sen Jianga4365d62015-09-25 10:52:25 -07001//
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
Alex Deymo39910dc2015-11-09 17:04:30 -080017#include "update_engine/payload_consumer/delta_performer.h"
Sen Jianga4365d62015-09-25 10:52:25 -070018
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>
Sen Jianga4365d62015-09-25 10:52:25 -070028#include <base/strings/string_util.h>
Alex Deymoe5e5fe92015-10-05 09:28:19 -070029#include <base/strings/stringprintf.h>
Sen Jianga4365d62015-09-25 10:52:25 -070030#include <google/protobuf/repeated_field.h>
31#include <gtest/gtest.h>
Sen Jiang8de733a2016-03-25 13:57:49 -070032#include <openssl/pem.h>
Sen Jianga4365d62015-09-25 10:52:25 -070033
Alex Deymo39910dc2015-11-09 17:04:30 -080034#include "update_engine/common/constants.h"
Alex Deymo542c19b2015-12-03 07:43:31 -030035#include "update_engine/common/fake_boot_control.h"
Alex Deymo39910dc2015-11-09 17:04:30 -080036#include "update_engine/common/fake_hardware.h"
37#include "update_engine/common/mock_prefs.h"
38#include "update_engine/common/test_utils.h"
39#include "update_engine/common/utils.h"
Alex Deymo542c19b2015-12-03 07:43:31 -030040#include "update_engine/payload_consumer/mock_download_action.h"
Alex Deymo39910dc2015-11-09 17:04:30 -080041#include "update_engine/payload_consumer/payload_constants.h"
Sen Jiang44ac3ea2018-10-18 15:10:20 -070042#include "update_engine/payload_consumer/payload_metadata.h"
Alex Deymo39910dc2015-11-09 17:04:30 -080043#include "update_engine/payload_consumer/payload_verifier.h"
Sen Jianga4365d62015-09-25 10:52:25 -070044#include "update_engine/payload_generator/delta_diff_generator.h"
45#include "update_engine/payload_generator/payload_signer.h"
Sen Jianga4365d62015-09-25 10:52:25 -070046#include "update_engine/update_metadata.pb.h"
Sen Jianga4365d62015-09-25 10:52:25 -070047
48namespace chromeos_update_engine {
49
50using std::string;
51using std::vector;
Sen Jiang260f03b2016-03-21 15:34:58 -070052using test_utils::GetBuildArtifactsPath;
Amin Hassani008c4582019-01-13 16:22:47 -080053using test_utils::kRandomString;
Sen Jianga4365d62015-09-25 10:52:25 -070054using test_utils::ScopedLoopMounter;
55using test_utils::System;
Alex Deymoe5e5fe92015-10-05 09:28:19 -070056using testing::_;
Amin Hassani008c4582019-01-13 16:22:47 -080057using testing::Return;
Sen Jianga4365d62015-09-25 10:52:25 -070058
59extern const char* kUnittestPrivateKeyPath;
60extern const char* kUnittestPublicKeyPath;
61extern const char* kUnittestPrivateKey2Path;
62extern const char* kUnittestPublicKey2Path;
63
Alex Deymo80f70ff2016-02-10 16:08:11 -080064static const uint32_t kDefaultKernelSize = 4096; // Something small for a test
Amin Hassani008c4582019-01-13 16:22:47 -080065// clang-format off
Sen Jianga4365d62015-09-25 10:52:25 -070066static const uint8_t kNewData[] = {'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
67 'n', 'e', 'w', ' ', 'd', 'a', 't', 'a', '.'};
Amin Hassani008c4582019-01-13 16:22:47 -080068// clang-format on
Sen Jianga4365d62015-09-25 10:52:25 -070069
70namespace {
71struct DeltaState {
72 string a_img;
73 string b_img;
74 string result_img;
75 size_t image_size;
76
77 string delta_path;
78 uint64_t metadata_size;
79
80 string old_kernel;
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070081 brillo::Blob old_kernel_data;
Sen Jianga4365d62015-09-25 10:52:25 -070082
83 string new_kernel;
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070084 brillo::Blob new_kernel_data;
Sen Jianga4365d62015-09-25 10:52:25 -070085
86 string result_kernel;
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070087 brillo::Blob result_kernel_data;
Sen Jianga4365d62015-09-25 10:52:25 -070088 size_t kernel_size;
89
Alex Deymoe5e5fe92015-10-05 09:28:19 -070090 // The InstallPlan referenced by the DeltaPerformer. This needs to outlive
91 // the DeltaPerformer.
92 InstallPlan install_plan;
93
Sen Jianga4365d62015-09-25 10:52:25 -070094 // The in-memory copy of delta file.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070095 brillo::Blob delta;
Sen Jianga4365d62015-09-25 10:52:25 -070096
Alex Deymo542c19b2015-12-03 07:43:31 -030097 // Mock and fake instances used by the delta performer.
98 FakeBootControl fake_boot_control_;
99 FakeHardware fake_hardware_;
100 MockDownloadActionDelegate mock_delegate_;
Sen Jianga4365d62015-09-25 10:52:25 -0700101};
102
103enum SignatureTest {
Amin Hassani008c4582019-01-13 16:22:47 -0800104 kSignatureNone, // No payload signing.
105 kSignatureGenerator, // Sign the payload at generation time.
106 kSignatureGenerated, // Sign the payload after it's generated.
Sen Jianga4365d62015-09-25 10:52:25 -0700107 kSignatureGeneratedPlaceholder, // Insert placeholder signatures, then real.
108 kSignatureGeneratedPlaceholderMismatch, // Insert a wrong sized placeholder.
109 kSignatureGeneratedShell, // Sign the generated payload through shell cmds.
Amin Hassani008c4582019-01-13 16:22:47 -0800110 kSignatureGeneratedShellBadKey, // Sign with a bad key through shell cmds.
Sen Jianga4365d62015-09-25 10:52:25 -0700111 kSignatureGeneratedShellRotateCl1, // Rotate key, test client v1
112 kSignatureGeneratedShellRotateCl2, // Rotate key, test client v2
113};
114
115enum OperationHashTest {
116 kInvalidOperationData,
117 kValidOperationData,
118};
119
120} // namespace
121
Sen Jiangdcaf7972018-05-11 16:03:23 -0700122class DeltaPerformerIntegrationTest : public ::testing::Test {};
Sen Jianga4365d62015-09-25 10:52:25 -0700123
Amin Hassani008c4582019-01-13 16:22:47 -0800124static void CompareFilesByBlock(const string& a_file,
125 const string& b_file,
Sen Jianga4365d62015-09-25 10:52:25 -0700126 size_t image_size) {
Alex Deymo80f70ff2016-02-10 16:08:11 -0800127 EXPECT_EQ(0U, image_size % kBlockSize);
Sen Jianga4365d62015-09-25 10:52:25 -0700128
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700129 brillo::Blob a_data, b_data;
Sen Jianga4365d62015-09-25 10:52:25 -0700130 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) {
Alex Deymo80f70ff2016-02-10 16:08:11 -0800136 EXPECT_EQ(0U, i % kBlockSize);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700137 brillo::Blob a_sub(&a_data[i], &a_data[i + kBlockSize]);
138 brillo::Blob b_sub(&b_data[i], &b_data[i + kBlockSize]);
Amin Hassani008c4582019-01-13 16:22:47 -0800139 EXPECT_TRUE(a_sub == b_sub) << "Block " << (i / kBlockSize) << " differs";
Sen Jianga4365d62015-09-25 10:52:25 -0700140 }
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
Sen Jiang990c27b2016-03-15 17:09:21 -0700159static bool WriteByteAtOffset(const string& path, off_t offset) {
160 int fd = open(path.c_str(), O_CREAT | O_WRONLY, 0644);
161 TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
162 ScopedFdCloser fd_closer(&fd);
163 EXPECT_TRUE(utils::PWriteAll(fd, "\0", 1, offset));
164 return true;
165}
166
Sen Jianga4365d62015-09-25 10:52:25 -0700167static size_t GetSignatureSize(const string& private_key_path) {
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700168 const brillo::Blob data(1, 'x');
169 brillo::Blob hash;
Alex Deymo39910dc2015-11-09 17:04:30 -0800170 EXPECT_TRUE(HashCalculator::RawHashOfData(data, &hash));
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700171 brillo::Blob signature;
Amin Hassani008c4582019-01-13 16:22:47 -0800172 EXPECT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature));
Sen Jianga4365d62015-09-25 10:52:25 -0700173 return signature.size();
174}
175
176static bool InsertSignaturePlaceholder(int signature_size,
177 const string& payload_path,
178 uint64_t* out_metadata_size) {
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700179 vector<brillo::Blob> signatures;
180 signatures.push_back(brillo::Blob(signature_size, 0));
Sen Jianga4365d62015-09-25 10:52:25 -0700181
182 return PayloadSigner::AddSignatureToPayload(
Amin Hassani008c4582019-01-13 16:22:47 -0800183 payload_path, signatures, {}, payload_path, out_metadata_size);
Sen Jianga4365d62015-09-25 10:52:25 -0700184}
185
186static void SignGeneratedPayload(const string& payload_path,
187 uint64_t* out_metadata_size) {
Sen Jiang260f03b2016-03-21 15:34:58 -0700188 string private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
189 int signature_size = GetSignatureSize(private_key_path);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700190 brillo::Blob hash;
Sen Jianga4365d62015-09-25 10:52:25 -0700191 ASSERT_TRUE(PayloadSigner::HashPayloadForSigning(
Sen Jiang260f03b2016-03-21 15:34:58 -0700192 payload_path, {signature_size}, &hash, nullptr));
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700193 brillo::Blob signature;
Sen Jiang260f03b2016-03-21 15:34:58 -0700194 ASSERT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature));
Sen Jianga4365d62015-09-25 10:52:25 -0700195 ASSERT_TRUE(PayloadSigner::AddSignatureToPayload(
Sen Jiang260f03b2016-03-21 15:34:58 -0700196 payload_path, {signature}, {}, payload_path, out_metadata_size));
Sen Jiangaef1c6f2015-10-07 10:05:32 -0700197 EXPECT_TRUE(PayloadSigner::VerifySignedPayload(
Sen Jiang260f03b2016-03-21 15:34:58 -0700198 payload_path, GetBuildArtifactsPath(kUnittestPublicKeyPath)));
Sen Jianga4365d62015-09-25 10:52:25 -0700199}
200
201static void SignGeneratedShellPayload(SignatureTest signature_test,
202 const string& payload_path) {
Sen Jiang260f03b2016-03-21 15:34:58 -0700203 string private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
Sen Jianga4365d62015-09-25 10:52:25 -0700204 if (signature_test == kSignatureGeneratedShellBadKey) {
Amin Hassani008c4582019-01-13 16:22:47 -0800205 ASSERT_TRUE(utils::MakeTempFile("key.XXXXXX", &private_key_path, nullptr));
Sen Jianga4365d62015-09-25 10:52:25 -0700206 } else {
207 ASSERT_TRUE(signature_test == kSignatureGeneratedShell ||
208 signature_test == kSignatureGeneratedShellRotateCl1 ||
209 signature_test == kSignatureGeneratedShellRotateCl2);
210 }
211 ScopedPathUnlinker key_unlinker(private_key_path);
212 key_unlinker.set_should_remove(signature_test ==
213 kSignatureGeneratedShellBadKey);
214 // Generates a new private key that will not match the public key.
215 if (signature_test == kSignatureGeneratedShellBadKey) {
216 LOG(INFO) << "Generating a mismatched private key.";
Sen Jiang8de733a2016-03-25 13:57:49 -0700217 // The code below executes the equivalent of:
218 // openssl genrsa -out <private_key_path> 2048
219 RSA* rsa = RSA_new();
220 BIGNUM* e = BN_new();
221 EXPECT_EQ(1, BN_set_word(e, RSA_F4));
222 EXPECT_EQ(1, RSA_generate_key_ex(rsa, 2048, e, nullptr));
223 BN_free(e);
224 FILE* fprikey = fopen(private_key_path.c_str(), "w");
225 EXPECT_NE(nullptr, fprikey);
226 EXPECT_EQ(1,
227 PEM_write_RSAPrivateKey(
228 fprikey, rsa, nullptr, nullptr, 0, nullptr, nullptr));
229 fclose(fprikey);
230 RSA_free(rsa);
Sen Jianga4365d62015-09-25 10:52:25 -0700231 }
232 int signature_size = GetSignatureSize(private_key_path);
Sen Jiang0779a152018-07-02 17:34:56 -0700233 test_utils::ScopedTempFile hash_file("hash.XXXXXX");
Sen Jianga4365d62015-09-25 10:52:25 -0700234 string signature_size_string;
235 if (signature_test == kSignatureGeneratedShellRotateCl1 ||
236 signature_test == kSignatureGeneratedShellRotateCl2)
Amin Hassani008c4582019-01-13 16:22:47 -0800237 signature_size_string =
238 base::StringPrintf("%d:%d", signature_size, signature_size);
Sen Jianga4365d62015-09-25 10:52:25 -0700239 else
240 signature_size_string = base::StringPrintf("%d", signature_size);
Sen Jiang5a216c12016-03-30 13:08:24 -0700241 string delta_generator_path = GetBuildArtifactsPath("delta_generator");
Sen Jianga4365d62015-09-25 10:52:25 -0700242 ASSERT_EQ(0,
243 System(base::StringPrintf(
Sen Jiang5a216c12016-03-30 13:08:24 -0700244 "%s -in_file=%s -signature_size=%s -out_hash_file=%s",
245 delta_generator_path.c_str(),
Sen Jianga4365d62015-09-25 10:52:25 -0700246 payload_path.c_str(),
247 signature_size_string.c_str(),
Sen Jiang0779a152018-07-02 17:34:56 -0700248 hash_file.path().c_str())));
Sen Jianga4365d62015-09-25 10:52:25 -0700249
Sen Jiang8de733a2016-03-25 13:57:49 -0700250 // Sign the hash
251 brillo::Blob hash, signature;
Sen Jiang0779a152018-07-02 17:34:56 -0700252 ASSERT_TRUE(utils::ReadFile(hash_file.path(), &hash));
Sen Jiang8de733a2016-03-25 13:57:49 -0700253 ASSERT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature));
Sen Jianga4365d62015-09-25 10:52:25 -0700254
Sen Jiang0779a152018-07-02 17:34:56 -0700255 test_utils::ScopedTempFile sig_file("signature.XXXXXX");
256 ASSERT_TRUE(test_utils::WriteFileVector(sig_file.path(), signature));
257 string sig_files = sig_file.path();
Sen Jiang8de733a2016-03-25 13:57:49 -0700258
Sen Jiang0779a152018-07-02 17:34:56 -0700259 test_utils::ScopedTempFile sig_file2("signature.XXXXXX");
Sen Jianga4365d62015-09-25 10:52:25 -0700260 if (signature_test == kSignatureGeneratedShellRotateCl1 ||
261 signature_test == kSignatureGeneratedShellRotateCl2) {
Sen Jiang8de733a2016-03-25 13:57:49 -0700262 ASSERT_TRUE(PayloadSigner::SignHash(
263 hash, GetBuildArtifactsPath(kUnittestPrivateKey2Path), &signature));
Sen Jiang0779a152018-07-02 17:34:56 -0700264 ASSERT_TRUE(test_utils::WriteFileVector(sig_file2.path(), signature));
Sen Jianga4365d62015-09-25 10:52:25 -0700265 // Append second sig file to first path
Sen Jiang0779a152018-07-02 17:34:56 -0700266 sig_files += ":" + sig_file2.path();
Sen Jianga4365d62015-09-25 10:52:25 -0700267 }
268
269 ASSERT_EQ(0,
270 System(base::StringPrintf(
Amin Hassanib4778292018-05-21 11:48:15 -0700271 "%s -in_file=%s -payload_signature_file=%s -out_file=%s",
Sen Jiang5a216c12016-03-30 13:08:24 -0700272 delta_generator_path.c_str(),
Sen Jianga4365d62015-09-25 10:52:25 -0700273 payload_path.c_str(),
Sen Jiang0779a152018-07-02 17:34:56 -0700274 sig_files.c_str(),
Sen Jianga4365d62015-09-25 10:52:25 -0700275 payload_path.c_str())));
Sen Jiang260f03b2016-03-21 15:34:58 -0700276 int verify_result = System(base::StringPrintf(
Sen Jiang5a216c12016-03-30 13:08:24 -0700277 "%s -in_file=%s -public_key=%s -public_key_version=%d",
278 delta_generator_path.c_str(),
Sen Jiang260f03b2016-03-21 15:34:58 -0700279 payload_path.c_str(),
280 (signature_test == kSignatureGeneratedShellRotateCl2
281 ? GetBuildArtifactsPath(kUnittestPublicKey2Path)
282 : GetBuildArtifactsPath(kUnittestPublicKeyPath))
283 .c_str(),
284 signature_test == kSignatureGeneratedShellRotateCl2 ? 2 : 1));
Sen Jianga4365d62015-09-25 10:52:25 -0700285 if (signature_test == kSignatureGeneratedShellBadKey) {
286 ASSERT_NE(0, verify_result);
287 } else {
288 ASSERT_EQ(0, verify_result);
289 }
290}
291
292static void GenerateDeltaFile(bool full_kernel,
293 bool full_rootfs,
294 bool noop,
295 ssize_t chunk_size,
296 SignatureTest signature_test,
Amin Hassani008c4582019-01-13 16:22:47 -0800297 DeltaState* state,
Sen Jianga4365d62015-09-25 10:52:25 -0700298 uint32_t minor_version) {
299 EXPECT_TRUE(utils::MakeTempFile("a_img.XXXXXX", &state->a_img, nullptr));
300 EXPECT_TRUE(utils::MakeTempFile("b_img.XXXXXX", &state->b_img, nullptr));
301
302 // result_img is used in minor version 2. Instead of applying the update
303 // in-place on A, we apply it to a new image, result_img.
304 EXPECT_TRUE(
305 utils::MakeTempFile("result_img.XXXXXX", &state->result_img, nullptr));
Sen Jiang990c27b2016-03-15 17:09:21 -0700306
Sen Jiang260f03b2016-03-21 15:34:58 -0700307 EXPECT_TRUE(
308 base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
309 base::FilePath(state->a_img)));
Sen Jianga4365d62015-09-25 10:52:25 -0700310
311 state->image_size = utils::FileSize(state->a_img);
312
Sen Jianga4365d62015-09-25 10:52:25 -0700313 // Create ImageInfo A & B
314 ImageInfo old_image_info;
315 ImageInfo new_image_info;
316
317 if (!full_rootfs) {
318 old_image_info.set_channel("src-channel");
319 old_image_info.set_board("src-board");
320 old_image_info.set_version("src-version");
321 old_image_info.set_key("src-key");
322 old_image_info.set_build_channel("src-build-channel");
323 old_image_info.set_build_version("src-build-version");
324 }
325
326 new_image_info.set_channel("test-channel");
327 new_image_info.set_board("test-board");
328 new_image_info.set_version("test-version");
329 new_image_info.set_key("test-key");
330 new_image_info.set_build_channel("test-build-channel");
331 new_image_info.set_build_version("test-build-version");
332
333 // Make some changes to the A image.
334 {
335 string a_mnt;
336 ScopedLoopMounter b_mounter(state->a_img, &a_mnt, 0);
337
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700338 brillo::Blob hardtocompress;
Sen Jianga4365d62015-09-25 10:52:25 -0700339 while (hardtocompress.size() < 3 * kBlockSize) {
340 hardtocompress.insert(hardtocompress.end(),
Amin Hassani008c4582019-01-13 16:22:47 -0800341 std::begin(kRandomString),
342 std::end(kRandomString));
Sen Jianga4365d62015-09-25 10:52:25 -0700343 }
Amin Hassani008c4582019-01-13 16:22:47 -0800344 EXPECT_TRUE(utils::WriteFile(
345 base::StringPrintf("%s/hardtocompress", a_mnt.c_str()).c_str(),
346 hardtocompress.data(),
347 hardtocompress.size()));
Sen Jianga4365d62015-09-25 10:52:25 -0700348
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700349 brillo::Blob zeros(16 * 1024, 0);
Alex Deymo80f70ff2016-02-10 16:08:11 -0800350 EXPECT_EQ(static_cast<int>(zeros.size()),
Sen Jianga4365d62015-09-25 10:52:25 -0700351 base::WriteFile(base::FilePath(base::StringPrintf(
352 "%s/move-to-sparse", a_mnt.c_str())),
353 reinterpret_cast<const char*>(zeros.data()),
354 zeros.size()));
355
Amin Hassani008c4582019-01-13 16:22:47 -0800356 EXPECT_TRUE(WriteSparseFile(
357 base::StringPrintf("%s/move-from-sparse", a_mnt.c_str()), 16 * 1024));
Sen Jianga4365d62015-09-25 10:52:25 -0700358
Sen Jiang990c27b2016-03-15 17:09:21 -0700359 EXPECT_TRUE(WriteByteAtOffset(
360 base::StringPrintf("%s/move-semi-sparse", a_mnt.c_str()), 4096));
Sen Jianga4365d62015-09-25 10:52:25 -0700361
362 // Write 1 MiB of 0xff to try to catch the case where writing a bsdiff
363 // patch fails to zero out the final block.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700364 brillo::Blob ones(1024 * 1024, 0xff);
Amin Hassani008c4582019-01-13 16:22:47 -0800365 EXPECT_TRUE(
366 utils::WriteFile(base::StringPrintf("%s/ones", a_mnt.c_str()).c_str(),
367 ones.data(),
368 ones.size()));
Sen Jianga4365d62015-09-25 10:52:25 -0700369 }
370
371 if (noop) {
372 EXPECT_TRUE(base::CopyFile(base::FilePath(state->a_img),
373 base::FilePath(state->b_img)));
374 old_image_info = new_image_info;
375 } else {
376 if (minor_version == kSourceMinorPayloadVersion) {
Sen Jiangf2af4c62015-09-30 16:38:09 -0700377 // Create a result image with image_size bytes of garbage.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700378 brillo::Blob ones(state->image_size, 0xff);
Amin Hassani008c4582019-01-13 16:22:47 -0800379 EXPECT_TRUE(utils::WriteFile(
380 state->result_img.c_str(), ones.data(), ones.size()));
Sen Jianga4365d62015-09-25 10:52:25 -0700381 EXPECT_EQ(utils::FileSize(state->a_img),
382 utils::FileSize(state->result_img));
383 }
384
Sen Jiang260f03b2016-03-21 15:34:58 -0700385 EXPECT_TRUE(
386 base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
387 base::FilePath(state->b_img)));
Sen Jianga4365d62015-09-25 10:52:25 -0700388
389 // Make some changes to the B image.
390 string b_mnt;
391 ScopedLoopMounter b_mounter(state->b_img, &b_mnt, 0);
Sen Jiang990c27b2016-03-15 17:09:21 -0700392 base::FilePath mnt_path(b_mnt);
Sen Jianga4365d62015-09-25 10:52:25 -0700393
Sen Jiang990c27b2016-03-15 17:09:21 -0700394 EXPECT_TRUE(base::CopyFile(mnt_path.Append("regular-small"),
395 mnt_path.Append("regular-small2")));
396 EXPECT_TRUE(base::DeleteFile(mnt_path.Append("regular-small"), false));
397 EXPECT_TRUE(base::Move(mnt_path.Append("regular-small2"),
398 mnt_path.Append("regular-small")));
399 EXPECT_TRUE(
400 test_utils::WriteFileString(mnt_path.Append("foo").value(), "foo"));
401 EXPECT_EQ(0, base::WriteFile(mnt_path.Append("emptyfile"), "", 0));
Sen Jianga4365d62015-09-25 10:52:25 -0700402
403 EXPECT_TRUE(
Sen Jiang990c27b2016-03-15 17:09:21 -0700404 WriteSparseFile(mnt_path.Append("fullsparse").value(), 1024 * 1024));
405 EXPECT_TRUE(
406 WriteSparseFile(mnt_path.Append("move-to-sparse").value(), 16 * 1024));
Sen Jianga4365d62015-09-25 10:52:25 -0700407
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700408 brillo::Blob zeros(16 * 1024, 0);
Alex Deymo80f70ff2016-02-10 16:08:11 -0800409 EXPECT_EQ(static_cast<int>(zeros.size()),
Sen Jiang990c27b2016-03-15 17:09:21 -0700410 base::WriteFile(mnt_path.Append("move-from-sparse"),
Sen Jianga4365d62015-09-25 10:52:25 -0700411 reinterpret_cast<const char*>(zeros.data()),
412 zeros.size()));
413
Sen Jiang990c27b2016-03-15 17:09:21 -0700414 EXPECT_TRUE(
415 WriteByteAtOffset(mnt_path.Append("move-semi-sparse").value(), 4096));
416 EXPECT_TRUE(WriteByteAtOffset(mnt_path.Append("partsparse").value(), 4096));
Sen Jianga4365d62015-09-25 10:52:25 -0700417
Sen Jiang990c27b2016-03-15 17:09:21 -0700418 EXPECT_TRUE(
419 base::CopyFile(mnt_path.Append("regular-16k"), mnt_path.Append("tmp")));
420 EXPECT_TRUE(base::Move(mnt_path.Append("tmp"),
421 mnt_path.Append("link-hard-regular-16k")));
422
423 EXPECT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink"), false));
424 EXPECT_TRUE(test_utils::WriteFileString(
425 mnt_path.Append("link-short_symlink").value(), "foobar"));
Sen Jianga4365d62015-09-25 10:52:25 -0700426
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700427 brillo::Blob hardtocompress;
Sen Jianga4365d62015-09-25 10:52:25 -0700428 while (hardtocompress.size() < 3 * kBlockSize) {
429 hardtocompress.insert(hardtocompress.end(),
Amin Hassani008c4582019-01-13 16:22:47 -0800430 std::begin(kRandomString),
431 std::end(kRandomString));
Sen Jianga4365d62015-09-25 10:52:25 -0700432 }
Amin Hassani008c4582019-01-13 16:22:47 -0800433 EXPECT_TRUE(utils::WriteFile(
434 base::StringPrintf("%s/hardtocompress", b_mnt.c_str()).c_str(),
435 hardtocompress.data(),
436 hardtocompress.size()));
Sen Jianga4365d62015-09-25 10:52:25 -0700437 }
438
439 string old_kernel;
Amin Hassani008c4582019-01-13 16:22:47 -0800440 EXPECT_TRUE(
441 utils::MakeTempFile("old_kernel.XXXXXX", &state->old_kernel, nullptr));
Sen Jianga4365d62015-09-25 10:52:25 -0700442
443 string new_kernel;
Amin Hassani008c4582019-01-13 16:22:47 -0800444 EXPECT_TRUE(
445 utils::MakeTempFile("new_kernel.XXXXXX", &state->new_kernel, nullptr));
Sen Jianga4365d62015-09-25 10:52:25 -0700446
447 string result_kernel;
Amin Hassani008c4582019-01-13 16:22:47 -0800448 EXPECT_TRUE(utils::MakeTempFile(
449 "result_kernel.XXXXXX", &state->result_kernel, nullptr));
Sen Jianga4365d62015-09-25 10:52:25 -0700450
451 state->kernel_size = kDefaultKernelSize;
452 state->old_kernel_data.resize(kDefaultKernelSize);
453 state->new_kernel_data.resize(state->old_kernel_data.size());
454 state->result_kernel_data.resize(state->old_kernel_data.size());
455 test_utils::FillWithData(&state->old_kernel_data);
456 test_utils::FillWithData(&state->new_kernel_data);
457 test_utils::FillWithData(&state->result_kernel_data);
458
459 // change the new kernel data
Amin Hassani008c4582019-01-13 16:22:47 -0800460 std::copy(
461 std::begin(kNewData), std::end(kNewData), state->new_kernel_data.begin());
Sen Jianga4365d62015-09-25 10:52:25 -0700462
463 if (noop) {
464 state->old_kernel_data = state->new_kernel_data;
465 }
466
467 // Write kernels to disk
468 EXPECT_TRUE(utils::WriteFile(state->old_kernel.c_str(),
469 state->old_kernel_data.data(),
470 state->old_kernel_data.size()));
471 EXPECT_TRUE(utils::WriteFile(state->new_kernel.c_str(),
472 state->new_kernel_data.data(),
473 state->new_kernel_data.size()));
474 EXPECT_TRUE(utils::WriteFile(state->result_kernel.c_str(),
475 state->result_kernel_data.data(),
476 state->result_kernel_data.size()));
477
Amin Hassani008c4582019-01-13 16:22:47 -0800478 EXPECT_TRUE(utils::MakeTempFile("delta.XXXXXX", &state->delta_path, nullptr));
Sen Jianga4365d62015-09-25 10:52:25 -0700479 LOG(INFO) << "delta path: " << state->delta_path;
480 {
481 const string private_key =
Sen Jiang260f03b2016-03-21 15:34:58 -0700482 signature_test == kSignatureGenerator
483 ? GetBuildArtifactsPath(kUnittestPrivateKeyPath)
484 : "";
Sen Jianga4365d62015-09-25 10:52:25 -0700485
486 PayloadGenerationConfig payload_config;
487 payload_config.is_delta = !full_rootfs;
488 payload_config.hard_chunk_size = chunk_size;
489 payload_config.rootfs_partition_size = kRootFSPartitionSize;
Alex Deymoa4073ef2016-03-22 23:40:53 -0700490 payload_config.version.major = kChromeOSMajorPayloadVersion;
491 payload_config.version.minor = minor_version;
Sen Jianga4365d62015-09-25 10:52:25 -0700492 if (!full_rootfs) {
Tudor Brindusdda79e22018-06-28 18:03:21 -0700493 payload_config.source.partitions.emplace_back(kPartitionNameRoot);
494 payload_config.source.partitions.emplace_back(kPartitionNameKernel);
Sen Jiang981eb112015-08-25 17:03:18 -0700495 payload_config.source.partitions.front().path = state->a_img;
Sen Jianga4365d62015-09-25 10:52:25 -0700496 if (!full_kernel)
Sen Jiang981eb112015-08-25 17:03:18 -0700497 payload_config.source.partitions.back().path = state->old_kernel;
Sen Jianga4365d62015-09-25 10:52:25 -0700498 payload_config.source.image_info = old_image_info;
499 EXPECT_TRUE(payload_config.source.LoadImageSize());
Sen Jiang981eb112015-08-25 17:03:18 -0700500 for (PartitionConfig& part : payload_config.source.partitions)
501 EXPECT_TRUE(part.OpenFilesystem());
Sen Jianga4365d62015-09-25 10:52:25 -0700502 } else {
503 if (payload_config.hard_chunk_size == -1)
504 // Use 1 MiB chunk size for the full unittests.
505 payload_config.hard_chunk_size = 1024 * 1024;
506 }
Tudor Brindusdda79e22018-06-28 18:03:21 -0700507 payload_config.target.partitions.emplace_back(kPartitionNameRoot);
Sen Jiang981eb112015-08-25 17:03:18 -0700508 payload_config.target.partitions.back().path = state->b_img;
Tudor Brindusdda79e22018-06-28 18:03:21 -0700509 payload_config.target.partitions.emplace_back(kPartitionNameKernel);
Sen Jiang981eb112015-08-25 17:03:18 -0700510 payload_config.target.partitions.back().path = state->new_kernel;
Sen Jianga4365d62015-09-25 10:52:25 -0700511 payload_config.target.image_info = new_image_info;
512 EXPECT_TRUE(payload_config.target.LoadImageSize());
Sen Jiang981eb112015-08-25 17:03:18 -0700513 for (PartitionConfig& part : payload_config.target.partitions)
514 EXPECT_TRUE(part.OpenFilesystem());
Sen Jianga4365d62015-09-25 10:52:25 -0700515
516 EXPECT_TRUE(payload_config.Validate());
Amin Hassani008c4582019-01-13 16:22:47 -0800517 EXPECT_TRUE(GenerateUpdatePayloadFile(
518 payload_config, state->delta_path, private_key, &state->metadata_size));
Sen Jianga4365d62015-09-25 10:52:25 -0700519 }
Sen Jiangf2af4c62015-09-30 16:38:09 -0700520 // Extend the "partitions" holding the file system a bit.
Amin Hassani008c4582019-01-13 16:22:47 -0800521 EXPECT_EQ(0,
522 HANDLE_EINTR(truncate(state->a_img.c_str(),
523 state->image_size + 1024 * 1024)));
Alex Deymo5fe0c4e2016-02-16 18:46:24 -0800524 EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
525 utils::FileSize(state->a_img));
Amin Hassani008c4582019-01-13 16:22:47 -0800526 EXPECT_EQ(0,
527 HANDLE_EINTR(truncate(state->b_img.c_str(),
528 state->image_size + 1024 * 1024)));
Alex Deymo5fe0c4e2016-02-16 18:46:24 -0800529 EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
530 utils::FileSize(state->b_img));
Sen Jianga4365d62015-09-25 10:52:25 -0700531
532 if (signature_test == kSignatureGeneratedPlaceholder ||
533 signature_test == kSignatureGeneratedPlaceholderMismatch) {
Sen Jiang260f03b2016-03-21 15:34:58 -0700534 int signature_size =
535 GetSignatureSize(GetBuildArtifactsPath(kUnittestPrivateKeyPath));
Sen Jianga4365d62015-09-25 10:52:25 -0700536 LOG(INFO) << "Inserting placeholder signature.";
Amin Hassani008c4582019-01-13 16:22:47 -0800537 ASSERT_TRUE(InsertSignaturePlaceholder(
538 signature_size, state->delta_path, &state->metadata_size));
Sen Jianga4365d62015-09-25 10:52:25 -0700539
540 if (signature_test == kSignatureGeneratedPlaceholderMismatch) {
541 signature_size -= 1;
542 LOG(INFO) << "Inserting mismatched placeholder signature.";
Amin Hassani008c4582019-01-13 16:22:47 -0800543 ASSERT_FALSE(InsertSignaturePlaceholder(
544 signature_size, state->delta_path, &state->metadata_size));
Sen Jianga4365d62015-09-25 10:52:25 -0700545 return;
546 }
547 }
548
549 if (signature_test == kSignatureGenerated ||
550 signature_test == kSignatureGeneratedPlaceholder ||
551 signature_test == kSignatureGeneratedPlaceholderMismatch) {
552 // Generate the signed payload and update the metadata size in state to
553 // reflect the new size after adding the signature operation to the
554 // manifest.
555 LOG(INFO) << "Signing payload.";
556 SignGeneratedPayload(state->delta_path, &state->metadata_size);
557 } else if (signature_test == kSignatureGeneratedShell ||
558 signature_test == kSignatureGeneratedShellBadKey ||
559 signature_test == kSignatureGeneratedShellRotateCl1 ||
560 signature_test == kSignatureGeneratedShellRotateCl2) {
561 SignGeneratedShellPayload(signature_test, state->delta_path);
562 }
563}
564
Amin Hassani008c4582019-01-13 16:22:47 -0800565static void ApplyDeltaFile(bool full_kernel,
566 bool full_rootfs,
567 bool noop,
568 SignatureTest signature_test,
569 DeltaState* state,
Sen Jianga4365d62015-09-25 10:52:25 -0700570 bool hash_checks_mandatory,
571 OperationHashTest op_hash_test,
572 DeltaPerformer** performer,
573 uint32_t minor_version) {
574 // Check the metadata.
575 {
Alex Deymo98e691c2016-02-04 21:05:45 -0800576 EXPECT_TRUE(utils::ReadFile(state->delta_path, &state->delta));
Sen Jiang44ac3ea2018-10-18 15:10:20 -0700577 PayloadMetadata payload_metadata;
578 EXPECT_TRUE(payload_metadata.ParsePayloadHeader(state->delta));
579 state->metadata_size = payload_metadata.GetMetadataSize();
580 LOG(INFO) << "Metadata size: " << state->metadata_size;
Sen Jianga4365d62015-09-25 10:52:25 -0700581
Sen Jiang44ac3ea2018-10-18 15:10:20 -0700582 DeltaArchiveManifest manifest;
583 EXPECT_TRUE(payload_metadata.GetManifest(state->delta, &manifest));
Sen Jianga4365d62015-09-25 10:52:25 -0700584 if (signature_test == kSignatureNone) {
585 EXPECT_FALSE(manifest.has_signatures_offset());
586 EXPECT_FALSE(manifest.has_signatures_size());
587 } else {
588 EXPECT_TRUE(manifest.has_signatures_offset());
589 EXPECT_TRUE(manifest.has_signatures_size());
590 Signatures sigs_message;
591 EXPECT_TRUE(sigs_message.ParseFromArray(
592 &state->delta[state->metadata_size + manifest.signatures_offset()],
593 manifest.signatures_size()));
594 if (signature_test == kSignatureGeneratedShellRotateCl1 ||
595 signature_test == kSignatureGeneratedShellRotateCl2)
596 EXPECT_EQ(2, sigs_message.signatures_size());
597 else
598 EXPECT_EQ(1, sigs_message.signatures_size());
599 const Signatures_Signature& signature = sigs_message.signatures(0);
Alex Deymo80f70ff2016-02-10 16:08:11 -0800600 EXPECT_EQ(1U, signature.version());
Sen Jianga4365d62015-09-25 10:52:25 -0700601
602 uint64_t expected_sig_data_length = 0;
Sen Jiang260f03b2016-03-21 15:34:58 -0700603 vector<string> key_paths{GetBuildArtifactsPath(kUnittestPrivateKeyPath)};
Sen Jianga4365d62015-09-25 10:52:25 -0700604 if (signature_test == kSignatureGeneratedShellRotateCl1 ||
605 signature_test == kSignatureGeneratedShellRotateCl2) {
Sen Jiang260f03b2016-03-21 15:34:58 -0700606 key_paths.push_back(GetBuildArtifactsPath(kUnittestPrivateKey2Path));
Sen Jianga4365d62015-09-25 10:52:25 -0700607 }
608 EXPECT_TRUE(PayloadSigner::SignatureBlobLength(
Amin Hassani008c4582019-01-13 16:22:47 -0800609 key_paths, &expected_sig_data_length));
Sen Jianga4365d62015-09-25 10:52:25 -0700610 EXPECT_EQ(expected_sig_data_length, manifest.signatures_size());
611 EXPECT_FALSE(signature.data().empty());
612 }
613
614 if (noop) {
615 EXPECT_EQ(0, manifest.install_operations_size());
616 EXPECT_EQ(1, manifest.kernel_install_operations_size());
617 }
618
619 if (full_kernel) {
620 EXPECT_FALSE(manifest.has_old_kernel_info());
621 } else {
622 EXPECT_EQ(state->old_kernel_data.size(),
623 manifest.old_kernel_info().size());
624 EXPECT_FALSE(manifest.old_kernel_info().hash().empty());
625 }
626
627 EXPECT_EQ(manifest.new_image_info().channel(), "test-channel");
628 EXPECT_EQ(manifest.new_image_info().board(), "test-board");
629 EXPECT_EQ(manifest.new_image_info().version(), "test-version");
630 EXPECT_EQ(manifest.new_image_info().key(), "test-key");
631 EXPECT_EQ(manifest.new_image_info().build_channel(), "test-build-channel");
632 EXPECT_EQ(manifest.new_image_info().build_version(), "test-build-version");
633
634 if (!full_rootfs) {
635 if (noop) {
636 EXPECT_EQ(manifest.old_image_info().channel(), "test-channel");
637 EXPECT_EQ(manifest.old_image_info().board(), "test-board");
638 EXPECT_EQ(manifest.old_image_info().version(), "test-version");
639 EXPECT_EQ(manifest.old_image_info().key(), "test-key");
640 EXPECT_EQ(manifest.old_image_info().build_channel(),
641 "test-build-channel");
642 EXPECT_EQ(manifest.old_image_info().build_version(),
643 "test-build-version");
644 } else {
645 EXPECT_EQ(manifest.old_image_info().channel(), "src-channel");
646 EXPECT_EQ(manifest.old_image_info().board(), "src-board");
647 EXPECT_EQ(manifest.old_image_info().version(), "src-version");
648 EXPECT_EQ(manifest.old_image_info().key(), "src-key");
649 EXPECT_EQ(manifest.old_image_info().build_channel(),
650 "src-build-channel");
651 EXPECT_EQ(manifest.old_image_info().build_version(),
652 "src-build-version");
653 }
654 }
655
Sen Jianga4365d62015-09-25 10:52:25 -0700656 if (full_rootfs) {
657 EXPECT_FALSE(manifest.has_old_rootfs_info());
658 EXPECT_FALSE(manifest.has_old_image_info());
659 EXPECT_TRUE(manifest.has_new_image_info());
660 } else {
661 EXPECT_EQ(state->image_size, manifest.old_rootfs_info().size());
662 EXPECT_FALSE(manifest.old_rootfs_info().hash().empty());
663 }
664
665 EXPECT_EQ(state->new_kernel_data.size(), manifest.new_kernel_info().size());
666 EXPECT_EQ(state->image_size, manifest.new_rootfs_info().size());
667
668 EXPECT_FALSE(manifest.new_kernel_info().hash().empty());
669 EXPECT_FALSE(manifest.new_rootfs_info().hash().empty());
670 }
671
672 MockPrefs prefs;
Amin Hassani008c4582019-01-13 16:22:47 -0800673 EXPECT_CALL(prefs, SetInt64(kPrefsManifestMetadataSize, state->metadata_size))
674 .WillOnce(Return(true));
Alex Deymof25eb492016-02-26 00:20:08 -0800675 EXPECT_CALL(prefs, SetInt64(kPrefsManifestSignatureSize, 0))
676 .WillOnce(Return(true));
Sen Jianga4365d62015-09-25 10:52:25 -0700677 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextOperation, _))
678 .WillRepeatedly(Return(true));
679 EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextOperation, _))
680 .WillOnce(Return(false));
681 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataOffset, _))
682 .WillRepeatedly(Return(true));
683 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataLength, _))
684 .WillRepeatedly(Return(true));
685 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSHA256Context, _))
686 .WillRepeatedly(Return(true));
Sen Jiang35f358b2015-11-05 10:46:32 -0800687 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignedSHA256Context, _))
688 .WillRepeatedly(Return(true));
Tao Bao3406c772019-01-02 15:34:35 -0800689 EXPECT_CALL(prefs, SetBoolean(kPrefsDynamicPartitionMetadataUpdated, _))
Yifan Hong28e89702018-12-05 03:28:47 +0000690 .WillRepeatedly(Return(true));
Sen Jianga4365d62015-09-25 10:52:25 -0700691 if (op_hash_test == kValidOperationData && signature_test != kSignatureNone) {
Sen Jianga4365d62015-09-25 10:52:25 -0700692 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignatureBlob, _))
693 .WillOnce(Return(true));
694 }
695
Alex Deymo542c19b2015-12-03 07:43:31 -0300696 EXPECT_CALL(state->mock_delegate_, ShouldCancel(_))
697 .WillRepeatedly(Return(false));
698
Sen Jianga4365d62015-09-25 10:52:25 -0700699 // Update the A image in place.
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700700 InstallPlan* install_plan = &state->install_plan;
701 install_plan->hash_checks_mandatory = hash_checks_mandatory;
Sen Jiangcdd52062017-05-18 15:33:10 -0700702 install_plan->payloads = {{.metadata_size = state->metadata_size,
703 .type = (full_kernel && full_rootfs)
704 ? InstallPayloadType::kFull
705 : InstallPayloadType::kDelta}};
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700706 install_plan->source_slot = 0;
707 install_plan->target_slot = 1;
708
709 InstallPlan::Partition root_part;
Tudor Brindusdda79e22018-06-28 18:03:21 -0700710 root_part.name = kPartitionNameRoot;
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700711
712 InstallPlan::Partition kernel_part;
Tudor Brindusdda79e22018-06-28 18:03:21 -0700713 kernel_part.name = kPartitionNameKernel;
Sen Jianga4365d62015-09-25 10:52:25 -0700714
715 LOG(INFO) << "Setting payload metadata size in Omaha = "
716 << state->metadata_size;
717 ASSERT_TRUE(PayloadSigner::GetMetadataSignature(
718 state->delta.data(),
719 state->metadata_size,
Sen Jiang260f03b2016-03-21 15:34:58 -0700720 GetBuildArtifactsPath(kUnittestPrivateKeyPath),
Sen Jiang0affc2c2017-02-10 15:55:05 -0800721 &install_plan->payloads[0].metadata_signature));
722 EXPECT_FALSE(install_plan->payloads[0].metadata_signature.empty());
Sen Jianga4365d62015-09-25 10:52:25 -0700723
724 *performer = new DeltaPerformer(&prefs,
Alex Deymo542c19b2015-12-03 07:43:31 -0300725 &state->fake_boot_control_,
726 &state->fake_hardware_,
727 &state->mock_delegate_,
Sen Jiang0affc2c2017-02-10 15:55:05 -0800728 install_plan,
Sen Jiang18414082018-01-11 14:50:36 -0800729 &install_plan->payloads[0],
Amin Hassanied37d682018-04-06 13:22:00 -0700730 false /* interactive */);
Sen Jiang260f03b2016-03-21 15:34:58 -0700731 string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath);
732 EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
733 (*performer)->set_public_key_path(public_key_path);
Sen Jianga4365d62015-09-25 10:52:25 -0700734
Alex Deymo5fe0c4e2016-02-16 18:46:24 -0800735 EXPECT_EQ(static_cast<off_t>(state->image_size),
Alex Deymo39910dc2015-11-09 17:04:30 -0800736 HashCalculator::RawHashOfFile(
Amin Hassani008c4582019-01-13 16:22:47 -0800737 state->a_img, state->image_size, &root_part.source_hash));
738 EXPECT_TRUE(HashCalculator::RawHashOfData(state->old_kernel_data,
739 &kernel_part.source_hash));
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700740
Sen Jiangd2ff2a02017-04-06 14:53:31 -0700741 // The partitions should be empty before DeltaPerformer.
742 install_plan->partitions.clear();
Sen Jianga4365d62015-09-25 10:52:25 -0700743
744 // With minor version 2, we want the target to be the new image, result_img,
745 // but with version 1, we want to update A in place.
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700746 string target_root, target_kernel;
Sen Jianga4365d62015-09-25 10:52:25 -0700747 if (minor_version == kSourceMinorPayloadVersion) {
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700748 target_root = state->result_img;
749 target_kernel = state->result_kernel;
Sen Jianga4365d62015-09-25 10:52:25 -0700750 } else {
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700751 target_root = state->a_img;
752 target_kernel = state->old_kernel;
Sen Jianga4365d62015-09-25 10:52:25 -0700753 }
754
Alex Deymo542c19b2015-12-03 07:43:31 -0300755 state->fake_boot_control_.SetPartitionDevice(
Tudor Brindusdda79e22018-06-28 18:03:21 -0700756 kPartitionNameRoot, install_plan->source_slot, state->a_img);
Alex Deymo542c19b2015-12-03 07:43:31 -0300757 state->fake_boot_control_.SetPartitionDevice(
Tudor Brindusdda79e22018-06-28 18:03:21 -0700758 kPartitionNameKernel, install_plan->source_slot, state->old_kernel);
Alex Deymo542c19b2015-12-03 07:43:31 -0300759 state->fake_boot_control_.SetPartitionDevice(
Tudor Brindusdda79e22018-06-28 18:03:21 -0700760 kPartitionNameRoot, install_plan->target_slot, target_root);
Alex Deymo542c19b2015-12-03 07:43:31 -0300761 state->fake_boot_control_.SetPartitionDevice(
Tudor Brindusdda79e22018-06-28 18:03:21 -0700762 kPartitionNameKernel, install_plan->target_slot, target_kernel);
Sen Jianga4365d62015-09-25 10:52:25 -0700763
764 ErrorCode expected_error, actual_error;
765 bool continue_writing;
766 switch (op_hash_test) {
767 case kInvalidOperationData: {
768 // Muck with some random offset post the metadata size so that
769 // some operation hash will result in a mismatch.
770 int some_offset = state->metadata_size + 300;
771 LOG(INFO) << "Tampered value at offset: " << some_offset;
772 state->delta[some_offset]++;
773 expected_error = ErrorCode::kDownloadOperationHashMismatch;
774 continue_writing = false;
775 break;
776 }
777
778 case kValidOperationData:
779 default:
780 // no change.
781 expected_error = ErrorCode::kSuccess;
782 continue_writing = true;
783 break;
784 }
785
786 // Write at some number of bytes per operation. Arbitrarily chose 5.
787 const size_t kBytesPerWrite = 5;
788 for (size_t i = 0; i < state->delta.size(); i += kBytesPerWrite) {
789 size_t count = std::min(state->delta.size() - i, kBytesPerWrite);
Amin Hassani008c4582019-01-13 16:22:47 -0800790 bool write_succeeded =
791 ((*performer)->Write(&state->delta[i], count, &actual_error));
Sen Jianga4365d62015-09-25 10:52:25 -0700792 // Normally write_succeeded should be true every time and
793 // actual_error should be ErrorCode::kSuccess. If so, continue the loop.
794 // But if we seeded an operation hash error above, then write_succeeded
795 // will be false. The failure may happen at any operation n. So, all
796 // Writes until n-1 should succeed and the nth operation will fail with
797 // actual_error. In this case, we should bail out of the loop because
798 // we cannot proceed applying the delta.
799 if (!write_succeeded) {
800 LOG(INFO) << "Write failed. Checking if it failed with expected error";
801 EXPECT_EQ(expected_error, actual_error);
802 if (!continue_writing) {
803 LOG(INFO) << "Cannot continue writing. Bailing out.";
804 break;
805 }
806 }
807
808 EXPECT_EQ(ErrorCode::kSuccess, actual_error);
809 }
810
811 // If we had continued all the way through, Close should succeed.
812 // Otherwise, it should fail. Check appropriately.
813 bool close_result = (*performer)->Close();
814 if (continue_writing)
815 EXPECT_EQ(0, close_result);
816 else
817 EXPECT_LE(0, close_result);
818}
819
820void VerifyPayloadResult(DeltaPerformer* performer,
821 DeltaState* state,
822 ErrorCode expected_result,
823 uint32_t minor_version) {
824 if (!performer) {
825 EXPECT_TRUE(!"Skipping payload verification since performer is null.");
826 return;
827 }
828
Sen Jiang2703ef42017-03-16 13:36:21 -0700829 LOG(INFO) << "Verifying payload for expected result " << expected_result;
830 brillo::Blob expected_hash;
831 HashCalculator::RawHashOfData(state->delta, &expected_hash);
832 EXPECT_EQ(expected_result,
833 performer->VerifyPayload(expected_hash, state->delta.size()));
Sen Jianga4365d62015-09-25 10:52:25 -0700834 LOG(INFO) << "Verified payload.";
835
836 if (expected_result != ErrorCode::kSuccess) {
837 // no need to verify new partition if VerifyPayload failed.
838 return;
839 }
840
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700841 brillo::Blob updated_kernel_partition;
Sen Jianga4365d62015-09-25 10:52:25 -0700842 if (minor_version == kSourceMinorPayloadVersion) {
Amin Hassani008c4582019-01-13 16:22:47 -0800843 CompareFilesByBlock(
844 state->result_kernel, state->new_kernel, state->kernel_size);
845 CompareFilesByBlock(state->result_img, state->b_img, state->image_size);
846 EXPECT_TRUE(
847 utils::ReadFile(state->result_kernel, &updated_kernel_partition));
Sen Jianga4365d62015-09-25 10:52:25 -0700848 } else {
Amin Hassani008c4582019-01-13 16:22:47 -0800849 CompareFilesByBlock(
850 state->old_kernel, state->new_kernel, state->kernel_size);
851 CompareFilesByBlock(state->a_img, state->b_img, state->image_size);
Sen Jianga4365d62015-09-25 10:52:25 -0700852 EXPECT_TRUE(utils::ReadFile(state->old_kernel, &updated_kernel_partition));
853 }
854
855 ASSERT_GE(updated_kernel_partition.size(), arraysize(kNewData));
Amin Hassani008c4582019-01-13 16:22:47 -0800856 EXPECT_TRUE(std::equal(std::begin(kNewData),
857 std::end(kNewData),
Sen Jianga4365d62015-09-25 10:52:25 -0700858 updated_kernel_partition.begin()));
859
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700860 const auto& partitions = state->install_plan.partitions;
Alex Deymo80f70ff2016-02-10 16:08:11 -0800861 EXPECT_EQ(2U, partitions.size());
Tudor Brindusdda79e22018-06-28 18:03:21 -0700862 EXPECT_EQ(kPartitionNameRoot, partitions[0].name);
863 EXPECT_EQ(kPartitionNameKernel, partitions[1].name);
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700864
865 EXPECT_EQ(kDefaultKernelSize, partitions[1].target_size);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700866 brillo::Blob expected_new_kernel_hash;
Alex Deymo39910dc2015-11-09 17:04:30 -0800867 EXPECT_TRUE(HashCalculator::RawHashOfData(state->new_kernel_data,
868 &expected_new_kernel_hash));
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700869 EXPECT_EQ(expected_new_kernel_hash, partitions[1].target_hash);
870
871 EXPECT_EQ(state->image_size, partitions[0].target_size);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700872 brillo::Blob expected_new_rootfs_hash;
Alex Deymo5fe0c4e2016-02-16 18:46:24 -0800873 EXPECT_EQ(static_cast<off_t>(state->image_size),
Amin Hassani008c4582019-01-13 16:22:47 -0800874 HashCalculator::RawHashOfFile(
875 state->b_img, state->image_size, &expected_new_rootfs_hash));
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700876 EXPECT_EQ(expected_new_rootfs_hash, partitions[0].target_hash);
Sen Jianga4365d62015-09-25 10:52:25 -0700877}
878
879void VerifyPayload(DeltaPerformer* performer,
880 DeltaState* state,
881 SignatureTest signature_test,
882 uint32_t minor_version) {
883 ErrorCode expected_result = ErrorCode::kSuccess;
884 switch (signature_test) {
885 case kSignatureNone:
886 expected_result = ErrorCode::kSignedDeltaPayloadExpectedError;
887 break;
888 case kSignatureGeneratedShellBadKey:
889 expected_result = ErrorCode::kDownloadPayloadPubKeyVerificationError;
890 break;
Amin Hassani008c4582019-01-13 16:22:47 -0800891 default:
892 break; // appease gcc
Sen Jianga4365d62015-09-25 10:52:25 -0700893 }
894
895 VerifyPayloadResult(performer, state, expected_result, minor_version);
896}
897
Amin Hassani008c4582019-01-13 16:22:47 -0800898void DoSmallImageTest(bool full_kernel,
899 bool full_rootfs,
900 bool noop,
Sen Jianga4365d62015-09-25 10:52:25 -0700901 ssize_t chunk_size,
902 SignatureTest signature_test,
Amin Hassani008c4582019-01-13 16:22:47 -0800903 bool hash_checks_mandatory,
904 uint32_t minor_version) {
Sen Jianga4365d62015-09-25 10:52:25 -0700905 DeltaState state;
Amin Hassani008c4582019-01-13 16:22:47 -0800906 DeltaPerformer* performer = nullptr;
907 GenerateDeltaFile(full_kernel,
908 full_rootfs,
909 noop,
910 chunk_size,
911 signature_test,
912 &state,
913 minor_version);
Sen Jianga4365d62015-09-25 10:52:25 -0700914
915 ScopedPathUnlinker a_img_unlinker(state.a_img);
916 ScopedPathUnlinker b_img_unlinker(state.b_img);
917 ScopedPathUnlinker new_img_unlinker(state.result_img);
918 ScopedPathUnlinker delta_unlinker(state.delta_path);
919 ScopedPathUnlinker old_kernel_unlinker(state.old_kernel);
920 ScopedPathUnlinker new_kernel_unlinker(state.new_kernel);
921 ScopedPathUnlinker result_kernel_unlinker(state.result_kernel);
Amin Hassani008c4582019-01-13 16:22:47 -0800922 ApplyDeltaFile(full_kernel,
923 full_rootfs,
924 noop,
925 signature_test,
926 &state,
927 hash_checks_mandatory,
928 kValidOperationData,
929 &performer,
930 minor_version);
Sen Jianga4365d62015-09-25 10:52:25 -0700931 VerifyPayload(performer, &state, signature_test, minor_version);
932 delete performer;
933}
934
935void DoOperationHashMismatchTest(OperationHashTest op_hash_test,
936 bool hash_checks_mandatory) {
937 DeltaState state;
Alex Deymocbf09892015-09-11 16:13:16 -0700938 uint64_t minor_version = kFullPayloadMinorVersion;
Amin Hassani008c4582019-01-13 16:22:47 -0800939 GenerateDeltaFile(
940 true, true, false, -1, kSignatureGenerated, &state, minor_version);
Sen Jianga4365d62015-09-25 10:52:25 -0700941 ScopedPathUnlinker a_img_unlinker(state.a_img);
942 ScopedPathUnlinker b_img_unlinker(state.b_img);
943 ScopedPathUnlinker delta_unlinker(state.delta_path);
944 ScopedPathUnlinker old_kernel_unlinker(state.old_kernel);
945 ScopedPathUnlinker new_kernel_unlinker(state.new_kernel);
Amin Hassani008c4582019-01-13 16:22:47 -0800946 DeltaPerformer* performer = nullptr;
947 ApplyDeltaFile(true,
948 true,
949 false,
950 kSignatureGenerated,
951 &state,
952 hash_checks_mandatory,
953 op_hash_test,
954 &performer,
Sen Jianga4365d62015-09-25 10:52:25 -0700955 minor_version);
956 delete performer;
957}
958
Sen Jianga4365d62015-09-25 10:52:25 -0700959TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageTest) {
Amin Hassani008c4582019-01-13 16:22:47 -0800960 DoSmallImageTest(false,
961 false,
962 false,
963 -1,
964 kSignatureGenerator,
965 false,
966 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -0700967}
968
Sen Jiang7ebfccf2018-03-15 13:55:55 -0700969TEST(DeltaPerformerIntegrationTest,
970 RunAsRootSmallImageSignaturePlaceholderTest) {
Amin Hassani008c4582019-01-13 16:22:47 -0800971 DoSmallImageTest(false,
972 false,
973 false,
974 -1,
975 kSignatureGeneratedPlaceholder,
976 false,
977 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -0700978}
979
Sen Jiang7ebfccf2018-03-15 13:55:55 -0700980TEST(DeltaPerformerIntegrationTest,
981 RunAsRootSmallImageSignaturePlaceholderMismatchTest) {
Sen Jianga4365d62015-09-25 10:52:25 -0700982 DeltaState state;
Amin Hassani008c4582019-01-13 16:22:47 -0800983 GenerateDeltaFile(false,
984 false,
985 false,
986 -1,
987 kSignatureGeneratedPlaceholderMismatch,
988 &state,
Sen Jianga4365d62015-09-25 10:52:25 -0700989 kInPlaceMinorPayloadVersion);
990}
991
992TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageChunksTest) {
Amin Hassani008c4582019-01-13 16:22:47 -0800993 DoSmallImageTest(false,
994 false,
995 false,
996 kBlockSize,
997 kSignatureGenerator,
998 false,
999 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001000}
1001
1002TEST(DeltaPerformerIntegrationTest, RunAsRootFullKernelSmallImageTest) {
Amin Hassani008c4582019-01-13 16:22:47 -08001003 DoSmallImageTest(true,
1004 false,
1005 false,
1006 -1,
1007 kSignatureGenerator,
1008 false,
1009 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001010}
1011
1012TEST(DeltaPerformerIntegrationTest, RunAsRootFullSmallImageTest) {
Amin Hassani008c4582019-01-13 16:22:47 -08001013 DoSmallImageTest(true,
1014 true,
1015 false,
1016 -1,
1017 kSignatureGenerator,
1018 true,
1019 kFullPayloadMinorVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001020}
1021
1022TEST(DeltaPerformerIntegrationTest, RunAsRootNoopSmallImageTest) {
Amin Hassani008c4582019-01-13 16:22:47 -08001023 DoSmallImageTest(false,
1024 false,
1025 true,
1026 -1,
1027 kSignatureGenerator,
1028 false,
1029 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001030}
1031
1032TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignNoneTest) {
Amin Hassani008c4582019-01-13 16:22:47 -08001033 DoSmallImageTest(false,
1034 false,
1035 false,
1036 -1,
1037 kSignatureNone,
1038 false,
1039 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001040}
1041
1042TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedTest) {
Amin Hassani008c4582019-01-13 16:22:47 -08001043 DoSmallImageTest(false,
1044 false,
1045 false,
1046 -1,
1047 kSignatureGenerated,
1048 true,
1049 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001050}
1051
1052TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSignGeneratedShellTest) {
Amin Hassani008c4582019-01-13 16:22:47 -08001053 DoSmallImageTest(false,
1054 false,
1055 false,
1056 -1,
1057 kSignatureGeneratedShell,
1058 false,
1059 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001060}
1061
Sen Jiang7ebfccf2018-03-15 13:55:55 -07001062TEST(DeltaPerformerIntegrationTest,
1063 RunAsRootSmallImageSignGeneratedShellBadKeyTest) {
Amin Hassani008c4582019-01-13 16:22:47 -08001064 DoSmallImageTest(false,
1065 false,
1066 false,
1067 -1,
1068 kSignatureGeneratedShellBadKey,
1069 false,
1070 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001071}
1072
Sen Jiang7ebfccf2018-03-15 13:55:55 -07001073TEST(DeltaPerformerIntegrationTest,
1074 RunAsRootSmallImageSignGeneratedShellRotateCl1Test) {
Amin Hassani008c4582019-01-13 16:22:47 -08001075 DoSmallImageTest(false,
1076 false,
1077 false,
1078 -1,
1079 kSignatureGeneratedShellRotateCl1,
1080 false,
1081 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001082}
1083
Sen Jiang7ebfccf2018-03-15 13:55:55 -07001084TEST(DeltaPerformerIntegrationTest,
1085 RunAsRootSmallImageSignGeneratedShellRotateCl2Test) {
Amin Hassani008c4582019-01-13 16:22:47 -08001086 DoSmallImageTest(false,
1087 false,
1088 false,
1089 -1,
1090 kSignatureGeneratedShellRotateCl2,
1091 false,
1092 kInPlaceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001093}
1094
1095TEST(DeltaPerformerIntegrationTest, RunAsRootSmallImageSourceOpsTest) {
Amin Hassani008c4582019-01-13 16:22:47 -08001096 DoSmallImageTest(false,
1097 false,
1098 false,
1099 -1,
1100 kSignatureGenerator,
1101 false,
1102 kSourceMinorPayloadVersion);
Sen Jianga4365d62015-09-25 10:52:25 -07001103}
1104
Sen Jiang7ebfccf2018-03-15 13:55:55 -07001105TEST(DeltaPerformerIntegrationTest,
1106 RunAsRootMandatoryOperationHashMismatchTest) {
Sen Jianga4365d62015-09-25 10:52:25 -07001107 DoOperationHashMismatchTest(kInvalidOperationData, true);
1108}
1109
1110} // namespace chromeos_update_engine