blob: fbacb36667b62fb1e049787e1509dc000acc32fd [file] [log] [blame]
Mike Frysinger8155d082012-04-06 15:23:18 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Andrew de los Reyes09e56d62010-04-23 13:45:53 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <sys/mount.h>
6#include <inttypes.h>
7
8#include <algorithm>
9#include <string>
10#include <vector>
11
Darin Petkov9fa7ec52010-10-18 11:45:23 -070012#include <base/file_util.h>
Chris Masoned903c3b2011-05-12 15:35:46 -070013#include <base/memory/scoped_ptr.h>
Darin Petkov73058b42010-10-06 16:32:19 -070014#include <base/string_util.h>
Mike Frysinger8155d082012-04-06 15:23:18 -040015#include <base/stringprintf.h>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070016#include <google/protobuf/repeated_field.h>
17#include <gtest/gtest.h>
18
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070019#include "update_engine/delta_diff_generator.h"
20#include "update_engine/delta_performer.h"
Andrew de los Reyes353777c2010-10-08 10:34:30 -070021#include "update_engine/extent_ranges.h"
Darin Petkov7a22d792010-11-08 14:10:00 -080022#include "update_engine/full_update_generator.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070023#include "update_engine/graph_types.h"
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070024#include "update_engine/payload_signer.h"
Darin Petkov73058b42010-10-06 16:32:19 -070025#include "update_engine/prefs_mock.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070026#include "update_engine/test_utils.h"
27#include "update_engine/update_metadata.pb.h"
28#include "update_engine/utils.h"
29
30namespace chromeos_update_engine {
31
32using std::min;
33using std::string;
34using std::vector;
Darin Petkov73058b42010-10-06 16:32:19 -070035using testing::_;
36using testing::Return;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070037
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070038extern const char* kUnittestPrivateKeyPath;
Darin Petkovd7061ab2010-10-06 14:37:09 -070039extern const char* kUnittestPublicKeyPath;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070040extern const char* kUnittestPrivateKey2Path;
41extern const char* kUnittestPublicKey2Path;
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070042
Andrew de los Reyes27f7d372010-10-07 11:26:07 -070043namespace {
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -080044const size_t kBlockSize = 4096;
Andrew de los Reyes27f7d372010-10-07 11:26:07 -070045} // namespace {}
46
47
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070048class DeltaPerformerTest : public ::testing::Test { };
49
50TEST(DeltaPerformerTest, ExtentsToByteStringTest) {
51 uint64_t test[] = {1, 1, 4, 2, kSparseHole, 1, 0, 1};
52 COMPILE_ASSERT(arraysize(test) % 2 == 0, array_size_uneven);
53 const uint64_t block_size = 4096;
54 const uint64_t file_length = 5 * block_size - 13;
55
56 google::protobuf::RepeatedPtrField<Extent> extents;
57 for (size_t i = 0; i < arraysize(test); i += 2) {
58 Extent* extent = extents.Add();
59 extent->set_start_block(test[i]);
60 extent->set_num_blocks(test[i + 1]);
61 }
62
63 string expected_output = "4096:4096,16384:8192,-1:4096,0:4083";
64 string actual_output;
65 EXPECT_TRUE(DeltaPerformer::ExtentsToBsdiffPositionsString(extents,
66 block_size,
67 file_length,
68 &actual_output));
69 EXPECT_EQ(expected_output, actual_output);
70}
71
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070072void CompareFilesByBlock(const string& a_file, const string& b_file) {
73 vector<char> a_data, b_data;
Andrew de los Reyes3270f742010-07-15 22:28:14 -070074 EXPECT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file;
75 EXPECT_TRUE(utils::ReadFile(b_file, &b_data)) << "file failed: " << b_file;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070076
77 EXPECT_EQ(a_data.size(), b_data.size());
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070078 EXPECT_EQ(0, a_data.size() % kBlockSize);
79 for (size_t i = 0; i < a_data.size(); i += kBlockSize) {
80 EXPECT_EQ(0, i % kBlockSize);
81 vector<char> a_sub(&a_data[i], &a_data[i + kBlockSize]);
82 vector<char> b_sub(&b_data[i], &b_data[i + kBlockSize]);
83 EXPECT_TRUE(a_sub == b_sub) << "Block " << (i/kBlockSize) << " differs";
84 }
85}
86
87namespace {
88bool WriteSparseFile(const string& path, off_t size) {
89 int fd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
90 TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
91 ScopedFdCloser fd_closer(&fd);
92 off_t rc = lseek(fd, size + 1, SEEK_SET);
93 TEST_AND_RETURN_FALSE_ERRNO(rc != static_cast<off_t>(-1));
94 int return_code = ftruncate(fd, size);
95 TEST_AND_RETURN_FALSE_ERRNO(return_code == 0);
96 return true;
97}
Darin Petkov9574f7e2011-01-13 10:48:12 -080098} // namespace {}
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070099
Darin Petkov9574f7e2011-01-13 10:48:12 -0800100namespace {
Darin Petkovcbfb0172011-01-14 15:24:45 -0800101enum SignatureTest {
102 kSignatureNone, // No payload signing.
103 kSignatureGenerator, // Sign the payload at generation time.
104 kSignatureGenerated, // Sign the payload after it's generated.
105 kSignatureGeneratedShell, // Sign the generated payload through shell cmds.
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800106 kSignatureGeneratedShellBadKey, // Sign with a bad key through shell cmds.
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700107 kSignatureGeneratedShellRotateCl1, // Rotate key, test client v1
108 kSignatureGeneratedShellRotateCl2, // Rotate key, test client v2
Darin Petkovcbfb0172011-01-14 15:24:45 -0800109};
110
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800111size_t GetSignatureSize(const string& private_key_path) {
Darin Petkovcbfb0172011-01-14 15:24:45 -0800112 const vector<char> data(1, 'x');
113 vector<char> hash;
114 EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(data, &hash));
115 vector<char> signature;
116 EXPECT_TRUE(PayloadSigner::SignHash(hash,
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800117 private_key_path,
Darin Petkovcbfb0172011-01-14 15:24:45 -0800118 &signature));
119 return signature.size();
120}
121
122void SignGeneratedPayload(const string& payload_path) {
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800123 int signature_size = GetSignatureSize(kUnittestPrivateKeyPath);
Darin Petkovcbfb0172011-01-14 15:24:45 -0800124 vector<char> hash;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700125 ASSERT_TRUE(PayloadSigner::HashPayloadForSigning(
126 payload_path,
127 vector<int>(1, signature_size),
128 &hash));
Darin Petkovcbfb0172011-01-14 15:24:45 -0800129 vector<char> signature;
130 ASSERT_TRUE(PayloadSigner::SignHash(hash,
131 kUnittestPrivateKeyPath,
132 &signature));
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700133 ASSERT_TRUE(PayloadSigner::AddSignatureToPayload(
134 payload_path,
135 vector<vector<char> >(1, signature),
136 payload_path));
137 EXPECT_TRUE(PayloadSigner::VerifySignedPayload(
138 payload_path,
139 kUnittestPublicKeyPath,
140 kSignatureMessageOriginalVersion));
Darin Petkovcbfb0172011-01-14 15:24:45 -0800141}
142
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800143void SignGeneratedShellPayload(SignatureTest signature_test,
144 const string& payload_path) {
145 string private_key_path = kUnittestPrivateKeyPath;
146 if (signature_test == kSignatureGeneratedShellBadKey) {
147 ASSERT_TRUE(utils::MakeTempFile("/tmp/key.XXXXXX",
148 &private_key_path,
149 NULL));
150 } else {
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700151 ASSERT_TRUE(signature_test == kSignatureGeneratedShell ||
152 signature_test == kSignatureGeneratedShellRotateCl1 ||
153 signature_test == kSignatureGeneratedShellRotateCl2);
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800154 }
155 ScopedPathUnlinker key_unlinker(private_key_path);
156 key_unlinker.set_should_remove(signature_test ==
157 kSignatureGeneratedShellBadKey);
158 // Generates a new private key that will not match the public key.
159 if (signature_test == kSignatureGeneratedShellBadKey) {
160 LOG(INFO) << "Generating a mismatched private key.";
161 ASSERT_EQ(0,
162 System(StringPrintf(
Mike Frysinger2149be42012-03-12 19:23:47 -0400163 "openssl genrsa -out %s 2048",
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800164 private_key_path.c_str())));
165 }
166 int signature_size = GetSignatureSize(private_key_path);
Darin Petkovcbfb0172011-01-14 15:24:45 -0800167 string hash_file;
168 ASSERT_TRUE(utils::MakeTempFile("/tmp/hash.XXXXXX", &hash_file, NULL));
169 ScopedPathUnlinker hash_unlinker(hash_file);
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700170 string signature_size_string;
171 if (signature_test == kSignatureGeneratedShellRotateCl1 ||
172 signature_test == kSignatureGeneratedShellRotateCl2)
173 signature_size_string = StringPrintf("%d:%d",
174 signature_size, signature_size);
175 else
176 signature_size_string = StringPrintf("%d", signature_size);
Darin Petkovcbfb0172011-01-14 15:24:45 -0800177 ASSERT_EQ(0,
178 System(StringPrintf(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700179 "./delta_generator -in_file %s -signature_size %s "
Darin Petkovcbfb0172011-01-14 15:24:45 -0800180 "-out_hash_file %s",
181 payload_path.c_str(),
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700182 signature_size_string.c_str(),
Darin Petkovcbfb0172011-01-14 15:24:45 -0800183 hash_file.c_str())));
184
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700185 // Pad the hash
186 vector<char> hash;
187 ASSERT_TRUE(utils::ReadFile(hash_file, &hash));
188 ASSERT_TRUE(PayloadSigner::PadRSA2048SHA256Hash(&hash));
189 ASSERT_TRUE(WriteFileVector(hash_file, hash));
190
Darin Petkovcbfb0172011-01-14 15:24:45 -0800191 string sig_file;
192 ASSERT_TRUE(utils::MakeTempFile("/tmp/signature.XXXXXX", &sig_file, NULL));
193 ScopedPathUnlinker sig_unlinker(sig_file);
194 ASSERT_EQ(0,
195 System(StringPrintf(
Mike Frysinger2149be42012-03-12 19:23:47 -0400196 "openssl rsautl -raw -sign -inkey %s -in %s -out %s",
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800197 private_key_path.c_str(),
Darin Petkovcbfb0172011-01-14 15:24:45 -0800198 hash_file.c_str(),
199 sig_file.c_str())));
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700200 string sig_file2;
201 ASSERT_TRUE(utils::MakeTempFile("/tmp/signature.XXXXXX", &sig_file2, NULL));
202 ScopedPathUnlinker sig2_unlinker(sig_file2);
203 if (signature_test == kSignatureGeneratedShellRotateCl1 ||
204 signature_test == kSignatureGeneratedShellRotateCl2) {
205 ASSERT_EQ(0,
206 System(StringPrintf(
Mike Frysinger2149be42012-03-12 19:23:47 -0400207 "openssl rsautl -raw -sign -inkey %s -in %s -out %s",
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700208 kUnittestPrivateKey2Path,
209 hash_file.c_str(),
210 sig_file2.c_str())));
211 // Append second sig file to first path
212 sig_file += ":" + sig_file2;
213 }
214
Darin Petkovcbfb0172011-01-14 15:24:45 -0800215 ASSERT_EQ(0,
216 System(StringPrintf(
217 "./delta_generator -in_file %s -signature_file %s "
218 "-out_file %s",
219 payload_path.c_str(),
220 sig_file.c_str(),
221 payload_path.c_str())));
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800222 int verify_result =
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700223 System(StringPrintf(
224 "./delta_generator -in_file %s -public_key %s -public_key_version %d",
225 payload_path.c_str(),
226 signature_test == kSignatureGeneratedShellRotateCl2 ?
227 kUnittestPublicKey2Path : kUnittestPublicKeyPath,
228 signature_test == kSignatureGeneratedShellRotateCl2 ? 2 : 1));
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800229 if (signature_test == kSignatureGeneratedShellBadKey) {
230 ASSERT_NE(0, verify_result);
231 } else {
232 ASSERT_EQ(0, verify_result);
233 }
Darin Petkovcbfb0172011-01-14 15:24:45 -0800234}
235
Darin Petkov9574f7e2011-01-13 10:48:12 -0800236void DoSmallImageTest(bool full_kernel, bool full_rootfs, bool noop,
Darin Petkovcbfb0172011-01-14 15:24:45 -0800237 SignatureTest signature_test) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700238 string a_img, b_img;
239 EXPECT_TRUE(utils::MakeTempFile("/tmp/a_img.XXXXXX", &a_img, NULL));
240 ScopedPathUnlinker a_img_unlinker(a_img);
241 EXPECT_TRUE(utils::MakeTempFile("/tmp/b_img.XXXXXX", &b_img, NULL));
242 ScopedPathUnlinker b_img_unlinker(b_img);
243
244 CreateExtImageAtPath(a_img, NULL);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700245
Darin Petkov7ea32332010-10-13 10:46:11 -0700246 int image_size = static_cast<int>(utils::FileSize(a_img));
247
248 // Extend the "partitions" holding the file system a bit.
249 EXPECT_EQ(0, System(base::StringPrintf(
250 "dd if=/dev/zero of=%s seek=%d bs=1 count=1",
251 a_img.c_str(),
252 image_size + 1024 * 1024 - 1)));
Darin Petkov7ea32332010-10-13 10:46:11 -0700253 EXPECT_EQ(image_size + 1024 * 1024, utils::FileSize(a_img));
Darin Petkov7ea32332010-10-13 10:46:11 -0700254
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700255 // Make some changes to the A image.
256 {
257 string a_mnt;
258 ScopedLoopMounter b_mounter(a_img, &a_mnt, 0);
259
260 EXPECT_TRUE(utils::WriteFile(StringPrintf("%s/hardtocompress",
261 a_mnt.c_str()).c_str(),
262 reinterpret_cast<const char*>(kRandomString),
263 sizeof(kRandomString) - 1));
264 // Write 1 MiB of 0xff to try to catch the case where writing a bsdiff
265 // patch fails to zero out the final block.
266 vector<char> ones(1024 * 1024, 0xff);
267 EXPECT_TRUE(utils::WriteFile(StringPrintf("%s/ones",
268 a_mnt.c_str()).c_str(),
269 &ones[0],
270 ones.size()));
271 }
272
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700273 if (noop) {
274 EXPECT_TRUE(file_util::CopyFile(FilePath(a_img), FilePath(b_img)));
275 } else {
276 CreateExtImageAtPath(b_img, NULL);
277 EXPECT_EQ(0, System(base::StringPrintf(
278 "dd if=/dev/zero of=%s seek=%d bs=1 count=1",
279 b_img.c_str(),
280 image_size + 1024 * 1024 - 1)));
281 EXPECT_EQ(image_size + 1024 * 1024, utils::FileSize(b_img));
282
283 // Make some changes to the B image.
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700284 string b_mnt;
285 ScopedLoopMounter b_mounter(b_img, &b_mnt, 0);
286
287 EXPECT_EQ(0, system(StringPrintf("cp %s/hello %s/hello2", b_mnt.c_str(),
288 b_mnt.c_str()).c_str()));
289 EXPECT_EQ(0, system(StringPrintf("rm %s/hello", b_mnt.c_str()).c_str()));
290 EXPECT_EQ(0, system(StringPrintf("mv %s/hello2 %s/hello", b_mnt.c_str(),
291 b_mnt.c_str()).c_str()));
292 EXPECT_EQ(0, system(StringPrintf("echo foo > %s/foo",
293 b_mnt.c_str()).c_str()));
294 EXPECT_EQ(0, system(StringPrintf("touch %s/emptyfile",
295 b_mnt.c_str()).c_str()));
296 EXPECT_TRUE(WriteSparseFile(StringPrintf("%s/fullsparse", b_mnt.c_str()),
297 1024 * 1024));
298 EXPECT_EQ(0, system(StringPrintf("dd if=/dev/zero of=%s/partsparese bs=1 "
299 "seek=4096 count=1",
300 b_mnt.c_str()).c_str()));
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800301 EXPECT_EQ(0, system(StringPrintf("cp %s/srchardlink0 %s/tmp && "
302 "mv %s/tmp %s/srchardlink1",
303 b_mnt.c_str(), b_mnt.c_str(),
304 b_mnt.c_str(), b_mnt.c_str()).c_str()));
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800305 EXPECT_EQ(0, system(StringPrintf("rm %s/boguslink && "
306 "echo foobar > %s/boguslink",
307 b_mnt.c_str(), b_mnt.c_str()).c_str()));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700308 EXPECT_TRUE(utils::WriteFile(StringPrintf("%s/hardtocompress",
309 b_mnt.c_str()).c_str(),
310 reinterpret_cast<const char*>(kRandomString),
311 sizeof(kRandomString)));
312 }
313
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700314 string old_kernel;
315 EXPECT_TRUE(utils::MakeTempFile("/tmp/old_kernel.XXXXXX", &old_kernel, NULL));
316 ScopedPathUnlinker old_kernel_unlinker(old_kernel);
317
318 string new_kernel;
319 EXPECT_TRUE(utils::MakeTempFile("/tmp/new_kernel.XXXXXX", &new_kernel, NULL));
320 ScopedPathUnlinker new_kernel_unlinker(new_kernel);
321
322 vector<char> old_kernel_data(4096); // Something small for a test
323 vector<char> new_kernel_data(old_kernel_data.size());
324 FillWithData(&old_kernel_data);
325 FillWithData(&new_kernel_data);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700326
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700327 // change the new kernel data
328 const char* new_data_string = "This is new data.";
329 strcpy(&new_kernel_data[0], new_data_string);
330
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700331 if (noop) {
332 old_kernel_data = new_kernel_data;
333 }
334
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700335 // Write kernels to disk
336 EXPECT_TRUE(utils::WriteFile(
337 old_kernel.c_str(), &old_kernel_data[0], old_kernel_data.size()));
338 EXPECT_TRUE(utils::WriteFile(
339 new_kernel.c_str(), &new_kernel_data[0], new_kernel_data.size()));
340
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700341 string delta_path;
342 EXPECT_TRUE(utils::MakeTempFile("/tmp/delta.XXXXXX", &delta_path, NULL));
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700343 LOG(INFO) << "delta path: " << delta_path;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700344 ScopedPathUnlinker delta_path_unlinker(delta_path);
345 {
346 string a_mnt, b_mnt;
347 ScopedLoopMounter a_mounter(a_img, &a_mnt, MS_RDONLY);
348 ScopedLoopMounter b_mounter(b_img, &b_mnt, MS_RDONLY);
Darin Petkovcbfb0172011-01-14 15:24:45 -0800349 const string private_key =
350 signature_test == kSignatureGenerator ? kUnittestPrivateKeyPath : "";
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700351 EXPECT_TRUE(
Darin Petkov68c10d12010-10-14 09:24:37 -0700352 DeltaDiffGenerator::GenerateDeltaUpdateFile(
Darin Petkov7a22d792010-11-08 14:10:00 -0800353 full_rootfs ? "" : a_mnt,
354 full_rootfs ? "" : a_img,
Darin Petkov68c10d12010-10-14 09:24:37 -0700355 b_mnt,
356 b_img,
357 full_kernel ? "" : old_kernel,
358 new_kernel,
359 delta_path,
Darin Petkovcbfb0172011-01-14 15:24:45 -0800360 private_key));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800361 }
362
Darin Petkovcbfb0172011-01-14 15:24:45 -0800363 if (signature_test == kSignatureGenerated) {
364 SignGeneratedPayload(delta_path);
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800365 } else if (signature_test == kSignatureGeneratedShell ||
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700366 signature_test == kSignatureGeneratedShellBadKey ||
367 signature_test == kSignatureGeneratedShellRotateCl1 ||
368 signature_test == kSignatureGeneratedShellRotateCl2) {
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800369 SignGeneratedShellPayload(signature_test, delta_path);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700370 }
371
372 // Read delta into memory.
373 vector<char> delta;
374 EXPECT_TRUE(utils::ReadFile(delta_path, &delta));
375
Darin Petkov73058b42010-10-06 16:32:19 -0700376 uint64_t manifest_metadata_size;
377
Darin Petkov36a58222010-10-07 22:00:09 -0700378 // Check the metadata.
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700379 {
380 LOG(INFO) << "delta size: " << delta.size();
381 DeltaArchiveManifest manifest;
382 const int kManifestSizeOffset = 12;
383 const int kManifestOffset = 20;
384 uint64_t manifest_size = 0;
385 memcpy(&manifest_size, &delta[kManifestSizeOffset], sizeof(manifest_size));
386 manifest_size = be64toh(manifest_size);
387 LOG(INFO) << "manifest size: " << manifest_size;
388 EXPECT_TRUE(manifest.ParseFromArray(&delta[kManifestOffset],
389 manifest_size));
Darin Petkov73058b42010-10-06 16:32:19 -0700390 manifest_metadata_size = kManifestOffset + manifest_size;
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700391
Darin Petkovcbfb0172011-01-14 15:24:45 -0800392 if (signature_test == kSignatureNone) {
393 EXPECT_FALSE(manifest.has_signatures_offset());
394 EXPECT_FALSE(manifest.has_signatures_size());
395 } else {
396 EXPECT_TRUE(manifest.has_signatures_offset());
397 EXPECT_TRUE(manifest.has_signatures_size());
398 Signatures sigs_message;
399 EXPECT_TRUE(sigs_message.ParseFromArray(
400 &delta[manifest_metadata_size + manifest.signatures_offset()],
401 manifest.signatures_size()));
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700402 if (signature_test == kSignatureGeneratedShellRotateCl1 ||
403 signature_test == kSignatureGeneratedShellRotateCl2)
404 EXPECT_EQ(2, sigs_message.signatures_size());
405 else
406 EXPECT_EQ(1, sigs_message.signatures_size());
Darin Petkovcbfb0172011-01-14 15:24:45 -0800407 const Signatures_Signature& signature = sigs_message.signatures(0);
408 EXPECT_EQ(1, signature.version());
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700409
Darin Petkovcbfb0172011-01-14 15:24:45 -0800410 uint64_t expected_sig_data_length = 0;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700411 vector<string> key_paths (1, kUnittestPrivateKeyPath);
412 if (signature_test == kSignatureGeneratedShellRotateCl1 ||
413 signature_test == kSignatureGeneratedShellRotateCl2) {
414 key_paths.push_back(kUnittestPrivateKey2Path);
415 }
Darin Petkovcbfb0172011-01-14 15:24:45 -0800416 EXPECT_TRUE(PayloadSigner::SignatureBlobLength(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700417 key_paths,
418 &expected_sig_data_length));
Darin Petkovcbfb0172011-01-14 15:24:45 -0800419 EXPECT_EQ(expected_sig_data_length, manifest.signatures_size());
420 EXPECT_FALSE(signature.data().empty());
421 }
Darin Petkov36a58222010-10-07 22:00:09 -0700422
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700423 if (noop) {
424 EXPECT_EQ(1, manifest.install_operations_size());
425 EXPECT_EQ(1, manifest.kernel_install_operations_size());
426 }
427
Darin Petkovd43d6902010-10-14 11:17:50 -0700428 if (full_kernel) {
429 EXPECT_FALSE(manifest.has_old_kernel_info());
430 } else {
431 EXPECT_EQ(old_kernel_data.size(), manifest.old_kernel_info().size());
432 EXPECT_FALSE(manifest.old_kernel_info().hash().empty());
433 }
Darin Petkov698d0412010-10-13 10:59:44 -0700434
Darin Petkov7a22d792010-11-08 14:10:00 -0800435 if (full_rootfs) {
436 EXPECT_FALSE(manifest.has_old_rootfs_info());
437 } else {
438 EXPECT_EQ(image_size, manifest.old_rootfs_info().size());
439 EXPECT_FALSE(manifest.old_rootfs_info().hash().empty());
440 }
441
Darin Petkov36a58222010-10-07 22:00:09 -0700442 EXPECT_EQ(new_kernel_data.size(), manifest.new_kernel_info().size());
Darin Petkov7ea32332010-10-13 10:46:11 -0700443 EXPECT_EQ(image_size, manifest.new_rootfs_info().size());
Darin Petkov36a58222010-10-07 22:00:09 -0700444
Darin Petkov36a58222010-10-07 22:00:09 -0700445 EXPECT_FALSE(manifest.new_kernel_info().hash().empty());
Darin Petkov36a58222010-10-07 22:00:09 -0700446 EXPECT_FALSE(manifest.new_rootfs_info().hash().empty());
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700447 }
448
Darin Petkov73058b42010-10-06 16:32:19 -0700449 PrefsMock prefs;
450 EXPECT_CALL(prefs, SetInt64(kPrefsManifestMetadataSize,
451 manifest_metadata_size)).WillOnce(Return(true));
452 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextOperation, _))
453 .WillRepeatedly(Return(true));
Darin Petkov9b230572010-10-08 10:20:09 -0700454 EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextOperation, _))
455 .WillOnce(Return(false));
Darin Petkov73058b42010-10-06 16:32:19 -0700456 EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextDataOffset, _))
457 .WillRepeatedly(Return(true));
Darin Petkov437adc42010-10-07 13:12:24 -0700458 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSHA256Context, _))
Darin Petkov73058b42010-10-06 16:32:19 -0700459 .WillRepeatedly(Return(true));
Darin Petkovcbfb0172011-01-14 15:24:45 -0800460 if (signature_test != kSignatureNone) {
461 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignedSHA256Context, _))
462 .WillOnce(Return(true));
Darin Petkov4f0a07b2011-05-25 16:47:20 -0700463 EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignatureBlob, _))
464 .WillOnce(Return(true));
Darin Petkovcbfb0172011-01-14 15:24:45 -0800465 }
Darin Petkov73058b42010-10-06 16:32:19 -0700466
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700467 // Update the A image in place.
Darin Petkov73058b42010-10-06 16:32:19 -0700468 DeltaPerformer performer(&prefs);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700469
Darin Petkovd43d6902010-10-14 11:17:50 -0700470 vector<char> rootfs_hash;
471 EXPECT_EQ(image_size,
472 OmahaHashCalculator::RawHashOfFile(a_img,
473 image_size,
474 &rootfs_hash));
Darin Petkov3aefa862010-12-07 14:45:00 -0800475 performer.set_current_rootfs_hash(rootfs_hash);
Darin Petkovd43d6902010-10-14 11:17:50 -0700476 vector<char> kernel_hash;
477 EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(old_kernel_data,
478 &kernel_hash));
Darin Petkov3aefa862010-12-07 14:45:00 -0800479 performer.set_current_kernel_hash(kernel_hash);
Darin Petkovd43d6902010-10-14 11:17:50 -0700480
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700481 EXPECT_EQ(0, performer.Open(a_img.c_str(), 0, 0));
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700482 EXPECT_TRUE(performer.OpenKernel(old_kernel.c_str()));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700483
484 // Write at some number of bytes per operation. Arbitrarily chose 5.
485 const size_t kBytesPerWrite = 5;
486 for (size_t i = 0; i < delta.size(); i += kBytesPerWrite) {
487 size_t count = min(delta.size() - i, kBytesPerWrite);
Don Garrette410e0f2011-11-10 15:39:01 -0800488 EXPECT_TRUE(performer.Write(&delta[i], count));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700489 }
490
491 // Wrapper around close. Returns 0 on success or -errno on error.
492 EXPECT_EQ(0, performer.Close());
493
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700494 CompareFilesByBlock(old_kernel, new_kernel);
Darin Petkov2dd01092010-10-08 15:43:05 -0700495 CompareFilesByBlock(a_img, b_img);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700496
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700497 vector<char> updated_kernel_partition;
498 EXPECT_TRUE(utils::ReadFile(old_kernel, &updated_kernel_partition));
499 EXPECT_EQ(0, strncmp(&updated_kernel_partition[0], new_data_string,
500 strlen(new_data_string)));
Darin Petkovd7061ab2010-10-06 14:37:09 -0700501
502 EXPECT_TRUE(utils::FileExists(kUnittestPublicKeyPath));
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -0700503 ActionExitCode expect_verify_result = kActionCodeSuccess;
504 switch (signature_test) {
505 case kSignatureNone:
506 expect_verify_result = kActionCodeSignedDeltaPayloadExpectedError;
507 break;
508 case kSignatureGeneratedShellBadKey:
509 expect_verify_result = kActionCodeDownloadPayloadPubKeyVerificationError;
510 break;
511 default: break; // appease gcc
512 }
513 EXPECT_EQ(expect_verify_result, performer.VerifyPayload(
Andrew de los Reyesfb830ba2011-04-04 11:42:43 -0700514 kUnittestPublicKeyPath,
515 OmahaHashCalculator::OmahaHashOfData(delta),
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -0700516 delta.size()));
517 EXPECT_EQ(kActionCodeSuccess, performer.VerifyPayload(
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800518 "/public/key/does/not/exists",
519 OmahaHashCalculator::OmahaHashOfData(delta),
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -0700520 delta.size()));
Darin Petkov3aefa862010-12-07 14:45:00 -0800521
522 uint64_t new_kernel_size;
523 vector<char> new_kernel_hash;
524 uint64_t new_rootfs_size;
525 vector<char> new_rootfs_hash;
526 EXPECT_TRUE(performer.GetNewPartitionInfo(&new_kernel_size,
527 &new_kernel_hash,
528 &new_rootfs_size,
529 &new_rootfs_hash));
530 EXPECT_EQ(4096, new_kernel_size);
531 vector<char> expected_new_kernel_hash;
532 EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(new_kernel_data,
533 &expected_new_kernel_hash));
534 EXPECT_TRUE(expected_new_kernel_hash == new_kernel_hash);
535 EXPECT_EQ(image_size, new_rootfs_size);
536 vector<char> expected_new_rootfs_hash;
537 EXPECT_EQ(image_size,
538 OmahaHashCalculator::RawHashOfFile(b_img,
539 image_size,
540 &expected_new_rootfs_hash));
541 EXPECT_TRUE(expected_new_rootfs_hash == new_rootfs_hash);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700542}
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700543} // namespace {}
Darin Petkov68c10d12010-10-14 09:24:37 -0700544
545TEST(DeltaPerformerTest, RunAsRootSmallImageTest) {
Darin Petkovcbfb0172011-01-14 15:24:45 -0800546 DoSmallImageTest(false, false, false, kSignatureGenerator);
Darin Petkov68c10d12010-10-14 09:24:37 -0700547}
548
549TEST(DeltaPerformerTest, RunAsRootFullKernelSmallImageTest) {
Darin Petkovcbfb0172011-01-14 15:24:45 -0800550 DoSmallImageTest(true, false, false, kSignatureGenerator);
Darin Petkov7a22d792010-11-08 14:10:00 -0800551}
552
553TEST(DeltaPerformerTest, RunAsRootFullSmallImageTest) {
Darin Petkovcbfb0172011-01-14 15:24:45 -0800554 DoSmallImageTest(true, true, false, kSignatureGenerator);
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700555}
556
557TEST(DeltaPerformerTest, RunAsRootNoopSmallImageTest) {
Darin Petkovcbfb0172011-01-14 15:24:45 -0800558 DoSmallImageTest(false, false, true, kSignatureGenerator);
Darin Petkov9574f7e2011-01-13 10:48:12 -0800559}
560
Darin Petkovcbfb0172011-01-14 15:24:45 -0800561TEST(DeltaPerformerTest, RunAsRootSmallImageSignNoneTest) {
562 DoSmallImageTest(false, false, false, kSignatureNone);
563}
564
565TEST(DeltaPerformerTest, RunAsRootSmallImageSignGeneratedTest) {
566 DoSmallImageTest(false, false, false, kSignatureGenerated);
567}
568
569TEST(DeltaPerformerTest, RunAsRootSmallImageSignGeneratedShellTest) {
570 DoSmallImageTest(false, false, false, kSignatureGeneratedShell);
Andrew de los Reyes27f7d372010-10-07 11:26:07 -0700571}
572
Darin Petkov52dcaeb2011-01-14 15:33:06 -0800573TEST(DeltaPerformerTest, RunAsRootSmallImageSignGeneratedShellBadKeyTest) {
574 DoSmallImageTest(false, false, false, kSignatureGeneratedShellBadKey);
575}
576
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700577TEST(DeltaPerformerTest, RunAsRootSmallImageSignGeneratedShellRotateCl1Test) {
578 DoSmallImageTest(false, false, false, kSignatureGeneratedShellRotateCl1);
579}
580
581TEST(DeltaPerformerTest, RunAsRootSmallImageSignGeneratedShellRotateCl2Test) {
582 DoSmallImageTest(false, false, false, kSignatureGeneratedShellRotateCl2);
583}
584
Darin Petkov934bb412010-11-18 11:21:35 -0800585TEST(DeltaPerformerTest, BadDeltaMagicTest) {
586 PrefsMock prefs;
587 DeltaPerformer performer(&prefs);
588 EXPECT_EQ(0, performer.Open("/dev/null", 0, 0));
589 EXPECT_TRUE(performer.OpenKernel("/dev/null"));
Don Garrette410e0f2011-11-10 15:39:01 -0800590 EXPECT_TRUE(performer.Write("junk", 4));
591 EXPECT_TRUE(performer.Write("morejunk", 8));
592 EXPECT_FALSE(performer.Write("morejunk", 8));
Darin Petkov934bb412010-11-18 11:21:35 -0800593 EXPECT_LT(performer.Close(), 0);
594}
595
Andrew de los Reyes353777c2010-10-08 10:34:30 -0700596TEST(DeltaPerformerTest, IsIdempotentOperationTest) {
597 DeltaArchiveManifest_InstallOperation op;
598 EXPECT_TRUE(DeltaPerformer::IsIdempotentOperation(op));
599 *(op.add_dst_extents()) = ExtentForRange(0, 5);
600 EXPECT_TRUE(DeltaPerformer::IsIdempotentOperation(op));
601 *(op.add_src_extents()) = ExtentForRange(4, 1);
602 EXPECT_FALSE(DeltaPerformer::IsIdempotentOperation(op));
603 op.clear_src_extents();
604 *(op.add_src_extents()) = ExtentForRange(5, 3);
605 EXPECT_TRUE(DeltaPerformer::IsIdempotentOperation(op));
606 *(op.add_dst_extents()) = ExtentForRange(20, 6);
607 EXPECT_TRUE(DeltaPerformer::IsIdempotentOperation(op));
608 *(op.add_src_extents()) = ExtentForRange(19, 2);
609 EXPECT_FALSE(DeltaPerformer::IsIdempotentOperation(op));
610}
611
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700612} // namespace chromeos_update_engine