blob: e09c1e7bac33354b393fd65efeb5237567bce182 [file] [log] [blame]
Jed Estepb8a693b2016-03-09 17:51:34 -08001/*
2 * Copyright (C) 2016 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 agree 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 <fcntl.h>
18#include <gtest/gtest.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <sys/stat.h>
22#include <sys/statvfs.h>
23#include <sys/types.h>
24#include <time.h>
25
Tao Baofada91c2016-10-27 18:16:06 -070026#include <memory>
Jed Estepb8a693b2016-03-09 17:51:34 -080027#include <string>
Tao Baofada91c2016-10-27 18:16:06 -070028#include <vector>
Jed Estepb8a693b2016-03-09 17:51:34 -080029
30#include <android-base/file.h>
31#include <android-base/stringprintf.h>
32#include <android-base/test_utils.h>
Tao Baofada91c2016-10-27 18:16:06 -070033#include <openssl/sha.h>
Jed Estepb8a693b2016-03-09 17:51:34 -080034
35#include "applypatch/applypatch.h"
36#include "common/test_constants.h"
Jed Estepb8a693b2016-03-09 17:51:34 -080037#include "print_sha1.h"
38
39static const std::string DATA_PATH = getenv("ANDROID_DATA");
40static const std::string TESTDATA_PATH = "/recovery/testdata";
Jed Estepb8a693b2016-03-09 17:51:34 -080041
Tao Baofada91c2016-10-27 18:16:06 -070042static void sha1sum(const std::string& fname, std::string* sha1) {
43 ASSERT_NE(nullptr, sha1);
44
Jed Estepb8a693b2016-03-09 17:51:34 -080045 std::string data;
Tao Baofada91c2016-10-27 18:16:06 -070046 ASSERT_TRUE(android::base::ReadFileToString(fname, &data));
Jed Estepb8a693b2016-03-09 17:51:34 -080047
Tao Baofada91c2016-10-27 18:16:06 -070048 uint8_t digest[SHA_DIGEST_LENGTH];
49 SHA1(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), digest);
50 *sha1 = print_sha1(digest);
Jed Estepb8a693b2016-03-09 17:51:34 -080051}
52
53static void mangle_file(const std::string& fname) {
Tao Baofada91c2016-10-27 18:16:06 -070054 std::string content;
55 content.reserve(1024);
56 for (size_t i = 0; i < 1024; i++) {
57 content[i] = rand() % 256;
Jed Estepb8a693b2016-03-09 17:51:34 -080058 }
Tao Baofada91c2016-10-27 18:16:06 -070059 ASSERT_TRUE(android::base::WriteStringToFile(content, fname));
Jed Estepb8a693b2016-03-09 17:51:34 -080060}
61
Tao Baofada91c2016-10-27 18:16:06 -070062static bool file_cmp(const std::string& f1, const std::string& f2) {
Jed Estepb8a693b2016-03-09 17:51:34 -080063 std::string c1;
Jed Estepb8a693b2016-03-09 17:51:34 -080064 android::base::ReadFileToString(f1, &c1);
Tao Baofada91c2016-10-27 18:16:06 -070065 std::string c2;
Jed Estepb8a693b2016-03-09 17:51:34 -080066 android::base::ReadFileToString(f2, &c2);
67 return c1 == c2;
68}
69
Chih-Hung Hsieh8b238112016-08-26 14:54:29 -070070static std::string from_testdata_base(const std::string& fname) {
Tao Baofada91c2016-10-27 18:16:06 -070071 return DATA_PATH + NATIVE_TEST_PATH + TESTDATA_PATH + "/" + fname;
Jed Estepb8a693b2016-03-09 17:51:34 -080072}
73
74class ApplyPatchTest : public ::testing::Test {
Tao Baofada91c2016-10-27 18:16:06 -070075 public:
76 static void SetUpTestCase() {
77 // set up files
78 old_file = from_testdata_base("old.file");
79 new_file = from_testdata_base("new.file");
80 patch_file = from_testdata_base("patch.bsdiff");
81 rand_file = "/cache/applypatch_test_rand.file";
82 cache_file = "/cache/saved.file";
Jed Estepb8a693b2016-03-09 17:51:34 -080083
Tao Baofada91c2016-10-27 18:16:06 -070084 // write stuff to rand_file
85 ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file));
Jed Estepb8a693b2016-03-09 17:51:34 -080086
Tao Baofada91c2016-10-27 18:16:06 -070087 // set up SHA constants
88 sha1sum(old_file, &old_sha1);
89 sha1sum(new_file, &new_sha1);
90 srand(time(NULL));
91 bad_sha1_a = android::base::StringPrintf("%040x", rand());
92 bad_sha1_b = android::base::StringPrintf("%040x", rand());
Jed Estepb8a693b2016-03-09 17:51:34 -080093
Tao Baofada91c2016-10-27 18:16:06 -070094 struct stat st;
95 stat(&new_file[0], &st);
96 new_size = st.st_size;
97 }
Jed Estepb8a693b2016-03-09 17:51:34 -080098
Tao Baofada91c2016-10-27 18:16:06 -070099 static std::string old_file;
100 static std::string new_file;
101 static std::string rand_file;
102 static std::string cache_file;
103 static std::string patch_file;
Jed Estepb8a693b2016-03-09 17:51:34 -0800104
Tao Baofada91c2016-10-27 18:16:06 -0700105 static std::string old_sha1;
106 static std::string new_sha1;
107 static std::string bad_sha1_a;
108 static std::string bad_sha1_b;
Jed Estepb8a693b2016-03-09 17:51:34 -0800109
Tao Baofada91c2016-10-27 18:16:06 -0700110 static size_t new_size;
Jed Estepb8a693b2016-03-09 17:51:34 -0800111};
112
113std::string ApplyPatchTest::old_file;
114std::string ApplyPatchTest::new_file;
115
Tao Baofada91c2016-10-27 18:16:06 -0700116static void cp(const std::string& src, const std::string& tgt) {
117 std::string cmd = "cp " + src + " " + tgt;
Jed Estepb8a693b2016-03-09 17:51:34 -0800118 system(&cmd[0]);
119}
120
121static void backup_old() {
122 cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file);
123}
124
125static void restore_old() {
126 cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file);
127}
128
129class ApplyPatchCacheTest : public ApplyPatchTest {
Tao Baofada91c2016-10-27 18:16:06 -0700130 public:
131 virtual void SetUp() {
132 backup_old();
133 }
Jed Estepb8a693b2016-03-09 17:51:34 -0800134
Tao Baofada91c2016-10-27 18:16:06 -0700135 virtual void TearDown() {
136 restore_old();
137 }
Jed Estepb8a693b2016-03-09 17:51:34 -0800138};
139
140class ApplyPatchFullTest : public ApplyPatchCacheTest {
Tao Baofada91c2016-10-27 18:16:06 -0700141 public:
142 static void SetUpTestCase() {
143 ApplyPatchTest::SetUpTestCase();
Jed Estepb8a693b2016-03-09 17:51:34 -0800144
Tao Baofada91c2016-10-27 18:16:06 -0700145 output_f = new TemporaryFile();
146 output_loc = std::string(output_f->path);
Jed Estepb8a693b2016-03-09 17:51:34 -0800147
Tao Baofada91c2016-10-27 18:16:06 -0700148 struct FileContents fc;
Jed Estepb8a693b2016-03-09 17:51:34 -0800149
Tao Baofada91c2016-10-27 18:16:06 -0700150 ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc));
151 patches.push_back(
152 std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())));
Jed Estepb8a693b2016-03-09 17:51:34 -0800153
Tao Baofada91c2016-10-27 18:16:06 -0700154 ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc));
155 patches.push_back(
156 std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())));
157 }
158
159 static void TearDownTestCase() {
160 delete output_f;
161 }
162
163 static std::vector<std::unique_ptr<Value>> patches;
164 static TemporaryFile* output_f;
165 static std::string output_loc;
Jed Estepb8a693b2016-03-09 17:51:34 -0800166};
167
168class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest {
Tao Baofada91c2016-10-27 18:16:06 -0700169 public:
170 virtual void SetUp() {
171 ApplyPatchCacheTest::SetUp();
172 cp(cache_file, "/cache/reallysaved.file");
173 }
Jed Estepb8a693b2016-03-09 17:51:34 -0800174
Tao Baofada91c2016-10-27 18:16:06 -0700175 virtual void TearDown() {
176 cp("/cache/reallysaved.file", cache_file);
177 ApplyPatchCacheTest::TearDown();
178 }
Jed Estepb8a693b2016-03-09 17:51:34 -0800179};
180
181std::string ApplyPatchTest::rand_file;
182std::string ApplyPatchTest::patch_file;
183std::string ApplyPatchTest::cache_file;
184std::string ApplyPatchTest::old_sha1;
185std::string ApplyPatchTest::new_sha1;
186std::string ApplyPatchTest::bad_sha1_a;
187std::string ApplyPatchTest::bad_sha1_b;
188
189size_t ApplyPatchTest::new_size;
190
Tao Baofada91c2016-10-27 18:16:06 -0700191std::vector<std::unique_ptr<Value>> ApplyPatchFullTest::patches;
Jed Estepb8a693b2016-03-09 17:51:34 -0800192TemporaryFile* ApplyPatchFullTest::output_f;
193std::string ApplyPatchFullTest::output_loc;
194
Tianjie Xua5fd5ab2016-10-18 15:18:22 -0700195TEST_F(ApplyPatchTest, CheckModeSkip) {
196 std::vector<std::string> sha1s;
197 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
198}
199
Jed Estepb8a693b2016-03-09 17:51:34 -0800200TEST_F(ApplyPatchTest, CheckModeSingle) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700201 std::vector<std::string> sha1s = { old_sha1 };
202 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800203}
204
205TEST_F(ApplyPatchTest, CheckModeMultiple) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700206 std::vector<std::string> sha1s = {
207 bad_sha1_a,
208 old_sha1,
209 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800210 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700211 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800212}
213
214TEST_F(ApplyPatchTest, CheckModeFailure) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700215 std::vector<std::string> sha1s = {
216 bad_sha1_a,
217 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800218 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700219 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800220}
221
222TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
223 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700224 std::vector<std::string> sha1s = { old_sha1 };
225 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800226}
227
228TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
229 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700230 std::vector<std::string> sha1s = {
231 bad_sha1_a,
232 old_sha1,
233 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800234 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700235 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800236}
237
238TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
239 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700240 std::vector<std::string> sha1s = {
241 bad_sha1_a,
242 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800243 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700244 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800245}
246
247TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
248 unlink(&old_file[0]);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700249 std::vector<std::string> sha1s = { old_sha1 };
250 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800251}
252
253TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
254 unlink(&old_file[0]);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700255 std::vector<std::string> sha1s = {
256 bad_sha1_a,
257 old_sha1,
258 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800259 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700260 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800261}
262
263TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
264 unlink(&old_file[0]);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700265 std::vector<std::string> sha1s = {
266 bad_sha1_a,
267 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800268 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700269 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800270}
271
272TEST_F(ApplyPatchFullTest, ApplyInPlace) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700273 std::vector<std::string> sha1s = {
274 bad_sha1_a,
275 old_sha1
276 };
Jed Estepb8a693b2016-03-09 17:51:34 -0800277 int ap_result = applypatch(&old_file[0],
278 "-",
279 &new_sha1[0],
280 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700281 sha1s,
Tao Baofada91c2016-10-27 18:16:06 -0700282 patches,
Jed Estepb8a693b2016-03-09 17:51:34 -0800283 nullptr);
284 ASSERT_EQ(0, ap_result);
285 ASSERT_TRUE(file_cmp(old_file, new_file));
286 // reapply, applypatch is idempotent so it should succeed
287 ap_result = applypatch(&old_file[0],
288 "-",
289 &new_sha1[0],
290 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700291 sha1s,
Tao Baofada91c2016-10-27 18:16:06 -0700292 patches,
Jed Estepb8a693b2016-03-09 17:51:34 -0800293 nullptr);
294 ASSERT_EQ(0, ap_result);
295 ASSERT_TRUE(file_cmp(old_file, new_file));
296}
297
298TEST_F(ApplyPatchFullTest, ApplyInNewLocation) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700299 std::vector<std::string> sha1s = {
300 bad_sha1_a,
301 old_sha1
302 };
Tao Baofada91c2016-10-27 18:16:06 -0700303 // Apply bsdiff patch to new location.
304 ASSERT_EQ(0, applypatch(&old_file[0],
Jed Estepb8a693b2016-03-09 17:51:34 -0800305 &output_loc[0],
306 &new_sha1[0],
307 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700308 sha1s,
Tao Baofada91c2016-10-27 18:16:06 -0700309 patches,
310 nullptr));
Jed Estepb8a693b2016-03-09 17:51:34 -0800311 ASSERT_TRUE(file_cmp(output_loc, new_file));
Tao Baofada91c2016-10-27 18:16:06 -0700312
313 // Reapply to the same location.
314 ASSERT_EQ(0, applypatch(&old_file[0],
Jed Estepb8a693b2016-03-09 17:51:34 -0800315 &output_loc[0],
316 &new_sha1[0],
317 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700318 sha1s,
Tao Baofada91c2016-10-27 18:16:06 -0700319 patches,
320 nullptr));
Jed Estepb8a693b2016-03-09 17:51:34 -0800321 ASSERT_TRUE(file_cmp(output_loc, new_file));
322}
323
324TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700325 std::vector<std::string> sha1s = {
326 bad_sha1_a,
327 old_sha1
328 };
Tao Baofada91c2016-10-27 18:16:06 -0700329 // Apply bsdiff patch to new location with corrupted source.
330 mangle_file(old_file);
Jed Estepb8a693b2016-03-09 17:51:34 -0800331 int ap_result = applypatch(&old_file[0],
332 &output_loc[0],
333 &new_sha1[0],
334 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700335 sha1s,
Tao Baofada91c2016-10-27 18:16:06 -0700336 patches,
Jed Estepb8a693b2016-03-09 17:51:34 -0800337 nullptr);
338 ASSERT_EQ(0, ap_result);
339 ASSERT_TRUE(file_cmp(output_loc, new_file));
Tao Baofada91c2016-10-27 18:16:06 -0700340
341 // Reapply bsdiff patch to new location with corrupted source.
Jed Estepb8a693b2016-03-09 17:51:34 -0800342 ap_result = applypatch(&old_file[0],
343 &output_loc[0],
344 &new_sha1[0],
345 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700346 sha1s,
Tao Baofada91c2016-10-27 18:16:06 -0700347 patches,
Jed Estepb8a693b2016-03-09 17:51:34 -0800348 nullptr);
349 ASSERT_EQ(0, ap_result);
350 ASSERT_TRUE(file_cmp(output_loc, new_file));
351}
352
353TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700354 std::vector<std::string> sha1s = {
355 bad_sha1_a,
356 old_sha1
357 };
Tao Baofada91c2016-10-27 18:16:06 -0700358
359 // Apply bsdiff patch to new location with corrupted source and copy (no new file).
360 // Expected to fail.
361 mangle_file(old_file);
362 mangle_file(cache_file);
Jed Estepb8a693b2016-03-09 17:51:34 -0800363 int ap_result = applypatch(&old_file[0],
364 &output_loc[0],
365 &new_sha1[0],
366 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700367 sha1s,
Tao Baofada91c2016-10-27 18:16:06 -0700368 patches,
Jed Estepb8a693b2016-03-09 17:51:34 -0800369 nullptr);
370 ASSERT_NE(0, ap_result);
371 ASSERT_FALSE(file_cmp(output_loc, new_file));
Tao Baofada91c2016-10-27 18:16:06 -0700372
373 // Expected to fail again on retry.
Jed Estepb8a693b2016-03-09 17:51:34 -0800374 ap_result = applypatch(&old_file[0],
375 &output_loc[0],
376 &new_sha1[0],
377 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700378 sha1s,
Tao Baofada91c2016-10-27 18:16:06 -0700379 patches,
380 nullptr);
381 ASSERT_NE(0, ap_result);
382 ASSERT_FALSE(file_cmp(output_loc, new_file));
383
384 // Expected to fail with incorrect new file.
385 mangle_file(output_loc);
386 ap_result = applypatch(&old_file[0],
387 &output_loc[0],
388 &new_sha1[0],
389 new_size,
390 sha1s,
391 patches,
Jed Estepb8a693b2016-03-09 17:51:34 -0800392 nullptr);
393 ASSERT_NE(0, ap_result);
394 ASSERT_FALSE(file_cmp(output_loc, new_file));
395}